* Fix numerous instances of shadowing confusion.
Inspired by a cppcon talk and our recent conversations about warnings, I
took a closer look at shadowing variables in our code and I wasn't proud
of my findings.
We had a lot of code that was writing to local variables or function
arguments when it thought it was operating on globals or (soon)
method-member variables. I made a rather half-hearted pass at changing
this by splitting up huge functions, renaming arguments, renaming globals
to reflect their future status as method variables (foo_), and generally
cleaning things up. The amound of effort I spent on each format was
approximately equal to its expected lifespan - I'm not spending an hour
on cleanups on formats I should instead be deleting.
In a future submit, I'll try to find some combination of -W flags on
our targets that allows us to not regress easily.
* Fix merge conflict I just created in gdb.cc
* Delete workspace.xml
* Delete the same link in garmin_icons.xml that I deleted twice yesterday.
Fix more esoteric warnings.
* Reapply MORE of yesterday's commits.
Seriously, I know this has been committed and is in HEAD...
* Attempt to fix list detachment within route.cc
* Remove Mapsource
The Mapsource format has been deprecated by Garmin for something
like 15 years. Later versions of Mapsource used GDB and Basecamp,
Garmin's first replacement for the Mapsource lineage, was used
exclusively in later versions.
I've reviewed list traffic and floated a discussion on the list.
The code style was never really very flexible and it it bears
a high maintenance cost that we can no longer afford. This
format is dead.
* Remove more pieces of Mapsource.
* Change Netstumbler test to not use Mapsource for staging.
More cleanups.
* Fix netstumbler so I can delete Mapsource. Ugh.
* Update netstumbler with IWYU.
add_definitions(${Qt5Core_DEFINITIONS})
set(MINIMAL_FMTS
- magproto.cc explorist_ini.cc gpx.cc geo.cc mapsend.cc mapsource.cc garmin.cc
+ magproto.cc explorist_ini.cc gpx.cc geo.cc mapsend.cc garmin.cc
garmin_device_xml.cc garmin_tables.cc internal_styles.cc nmea.cc
kml.cc wbt-200.cc
)
TEMPLATE = app
-MINIMAL_FMTS = magproto.cc explorist_ini.cc gpx.cc geo.cc mapsend.cc mapsource.cc garmin.cc \
+MINIMAL_FMTS = magproto.cc explorist_ini.cc gpx.cc geo.cc mapsend.cc garmin.cc \
garmin_device_xml.cc garmin_tables.cc internal_styles.cc nmea.cc \
kml.cc wbt-200.cc
PREFIX=@prefix@
INSTALL_DIR=$(DESTDIR)/$(PREFIX)
-MINIMAL_FMTS=magproto.o gpx.o geo.o mapsend.o mapsource.o garmin.o \
+MINIMAL_FMTS=magproto.o gpx.o geo.o mapsend.o garmin.o \
garmin_device_xml.o garmin_tables.o internal_styles.o nmea.o kml.o \
wbt-200.o ozi.o pcx.o gdb.o gtrnctr.o xcsv.o explorist_ini.o
mapsend.o: mapsend.cc defs.h config.h zlib/zlib.h zlib/zconf.h formspec.h \
inifile.h gbfile.h session.h src/core/datetime.h src/core/optional.h \
mapsend.h magellan.h
-mapsource.o: mapsource.cc defs.h config.h zlib/zlib.h zlib/zconf.h \
- formspec.h inifile.h gbfile.h session.h src/core/datetime.h \
- src/core/optional.h garmin_tables.h jeeps/gpsmath.h jeeps/gpsport.h
mkshort.o: mkshort.cc defs.h config.h zlib/zlib.h zlib/zconf.h formspec.h \
inifile.h gbfile.h session.h src/core/datetime.h src/core/optional.h \
cet.h
--- /dev/null
+/*
+ Access to Garmin MapSource files.
+ Based on information provided by Ian Cowley & Mark Bradley
+
+ Copyright (C) 2002 Robert Lipe, robertlipe+source@gpsbabel.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/* #define MPS_DEBUG 0 */
+
+#include <cstdio> // for SEEK_CUR, sprintf, SEEK_SET, EOF, size_t
+#include <cstdlib> // for atoi, rand, srand
+#include <cstring> // for strcpy, memset, strlen, strcmp
+#include <ctime> // for time_t
+#include <cstdio> // for SEEK_CUR
+
+#include <QtCore/QChar> // for QChar
+#include <QtCore/QFile> // for QFile
+#include <QtCore/QList> // for QList
+#include <QtCore/QString> // for QString, operator==
+#include <QtCore/QtGlobal> // for foreach
+
+#include "defs.h"
+#include "garmin_tables.h" // for gt_find_icon_number_from_desc, MAPSOURCE, gt_find_desc_from_icon_number, GARMIN_SERIAL, PCX, garmin_formats_e
+#include "gbfile.h" // for gbfwrite, gbfread, gbfgetint32, gbfputint32, gbfseek, gbfputc, gbfgetc, gbfputdbl, gbfgetdbl, gbfclose, gbfeof, gbfile, gbftell, gbfgetcstr, gbfputs, gbfopen_le
+#include "jeeps/gpsmath.h" // for GPS_Math_Deg_To_Semi, GPS_Math_Semi_To_Deg
+#include "src/core/datetime.h" // for DateTime
+
+
+static gbfile* mps_file_in;
+static gbfile* mps_file_out;
+static gbfile* mps_file_temp;
+static short_handle mkshort_handle;
+
+static int mps_ver_in = 0;
+static int mps_ver_out = 0;
+static int mps_ver_temp = 0;
+
+/* Temporary pathname used when merging gpsbabel output with an existing file */
+static QString tempname;
+static QString fin_name;
+
+static const Waypoint* prevRouteWpt;
+/* Private queues of written out waypoints */
+static QList<Waypoint *> written_wpt_head;
+static QList<Waypoint *> written_route_wpt_head;
+static short_handle written_wpt_mkshort_handle;
+
+/* Private queue of read in waypoints assumed to be used only for routes */
+static QList<Waypoint *> read_route_wpt_head;
+static short_handle read_route_wpt_mkshort_handle;
+
+#define MPSDEFAULTWPTCLASS 0
+#define MPSHIDDENROUTEWPTCLASS 8
+
+#define MYNAME "MAPSOURCE"
+#define ISME 0
+#define NOTME 1
+
+#define DEFAULTICONDESCR "Waypoint"
+#define DEFAULTICONVALUE 18
+
+#define MPSNAMEBUFFERLEN 1024
+#define MPSNOTESBUFFERLEN 4096
+#define MPSDESCBUFFERLEN 4096
+
+
+static char* snlen = nullptr;
+static char* snwhiteopt = nullptr;
+static char* mpsverout = nullptr;
+static char* mpsmergeouts = nullptr;
+static int mpsmergeout;
+static char* mpsusedepth = nullptr;
+static char* mpsuseprox = nullptr;
+
+static
+QVector<arglist_t> mps_args = {
+ {
+ "snlen", &snlen, "Length of generated shortnames", "10", ARGTYPE_INT, "1",
+ nullptr, nullptr
+ },
+ {
+ "snwhite", &snwhiteopt, "Allow whitespace synth. shortnames",
+ nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
+ {
+ "mpsverout", &mpsverout,
+ "Version of mapsource file to generate (3,4,5)", nullptr,
+ ARGTYPE_INT, ARG_NOMINMAX, nullptr
+ },
+ {
+ "mpsmergeout", &mpsmergeouts, "Merge output with existing file",
+ nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
+ {
+ "mpsusedepth", &mpsusedepth,
+ "Use depth values on output (default is ignore)", nullptr,
+ ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
+ {
+ "mpsuseprox", &mpsuseprox,
+ "Use proximity values on output (default is ignore)",
+ nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+ },
+};
+
+static void
+mps_wpt_q_init(QList<Waypoint *>* whichQueue)
+{
+ whichQueue->clear();
+}
+
+static void
+mps_wpt_q_deinit(QList<Waypoint *>* whichQueue)
+{
+ while (!whichQueue->isEmpty()) {
+ delete whichQueue->takeFirst();
+ }
+}
+
+/*
+ * Find a waypoint that we've already written out
+ *
+ */
+static Waypoint*
+mps_find_wpt_q_by_name(const QList<Waypoint *>* whichQueue, const QString& name)
+{
+ foreach (Waypoint* waypointp, *whichQueue) {
+ if (waypointp->shortname == name) {
+ return waypointp;
+ }
+ }
+ return nullptr;
+}
+
+/*
+ * Add a waypoint that we've already written out to our list
+ *
+ */
+static void
+mps_wpt_q_add(QList<Waypoint *>* whichQueue, const Waypoint* wpt)
+{
+ auto* written_wpt = new Waypoint(*wpt);
+ whichQueue->append(written_wpt);
+}
+
+static int
+mps_converted_icon_number(const int icon_num, const int mpsver, garmin_formats_e garmin_format)
+{
+ int def_icon = DEFAULTICONVALUE;
+
+ switch (garmin_format) {
+ case MAPSOURCE:
+ if (mpsver == 5) {
+ return icon_num;
+ }
+ if (mpsver == 4) {
+ /* Water hydrant */
+ if (icon_num == 139) {
+ return def_icon;
+ } else {
+ return icon_num;
+ }
+ } else {
+ /* the Contact icons - V3 doesn't have anything like this */
+ if ((icon_num >= 119) && (icon_num <= 138)) {
+ return def_icon;
+ }
+ /* the Geocache icons - V3 use the Circle with X */
+ if ((icon_num >= 117) && (icon_num <= 118)) {
+ return 65;
+ }
+ /* Water hydrant */
+ if (icon_num == 139) {
+ return def_icon;
+ }
+ return icon_num;
+ }
+
+ case PCX:
+ case GARMIN_SERIAL:
+ if (mpsver == 5) {
+ return icon_num;
+ }
+ if (mpsver == 4) {
+ /* Water hydrant */
+ if (icon_num == 8282) {
+ return def_icon;
+ } else {
+ return icon_num;
+ }
+ }
+ /* the Contact icons - V3 doesn't have anything like this */
+ if ((icon_num >= 8257) && (icon_num <= 8276)) {
+ return def_icon;
+ }
+ /* the Geocache icons - V3 use the Circle with X */
+ if ((icon_num >= 8255) && (icon_num <= 8256)) {
+ return 179;
+ }
+ /* Water hydrant */
+ if (icon_num == 8282) {
+ return def_icon;
+ }
+ return icon_num;
+
+ default:
+ fatal(MYNAME ": unknown garmin format.\n");
+ }
+ return def_icon;
+}
+
+static void
+mps_rd_init(const QString& fname)
+{
+ mps_file_in = gbfopen_le(fname, "rb", MYNAME);
+
+ read_route_wpt_mkshort_handle = mkshort_new_handle();
+ /* initialise the "private" queue of waypoints read for routes */
+ mps_wpt_q_init(&read_route_wpt_head);
+}
+
+static void
+mps_rd_deinit()
+{
+ gbfclose(mps_file_in);
+ if (read_route_wpt_mkshort_handle) {
+ mkshort_del_handle(&read_route_wpt_mkshort_handle);
+ }
+ /* flush the "private" queue of waypoints read for routes */
+ mps_wpt_q_deinit(&read_route_wpt_head);
+}
+
+static void
+mps_wr_init(const QString& fname)
+{
+ fin_name = fname;
+ if (mpsmergeouts) {
+ mpsmergeout = atoi(mpsmergeouts);
+ }
+
+ if (mpsmergeout) {
+ mps_file_out = gbfopen_le(fname, "rb", MYNAME);
+ if (mps_file_out == nullptr) {
+ mpsmergeout = 0;
+ } else {
+ gbfclose(mps_file_out);
+ srand((unsigned) current_time().toTime_t());
+
+ for (;;) {
+ /* create a temporary name based on a random char and the existing name */
+ /* then test if it already exists, if so try again with another rand num */
+ /* yeah, yeah, so there's probably a library function for this */
+ tempname = QString("%1.%2").arg(fname).arg(rand(), 8, 16, QChar('0'));
+ mps_file_temp = gbfopen_le(tempname, "rb", MYNAME);
+ if (mps_file_temp == nullptr) {
+ break;
+ }
+ gbfclose(mps_file_temp);
+ }
+ QFile::rename(fname, tempname);
+ mps_file_temp = gbfopen_le(tempname, "rb", MYNAME);
+ }
+ }
+
+ mps_file_out = gbfopen_le(fname, "wb", MYNAME);
+
+ written_wpt_mkshort_handle = mkshort_new_handle();
+ /* initialise the "private" queue of waypoints written */
+ mps_wpt_q_init(&written_wpt_head);
+ mps_wpt_q_init(&written_route_wpt_head);
+}
+
+static void
+mps_wr_deinit()
+{
+ gbfclose(mps_file_out);
+
+ if (mpsmergeout) {
+ gbfclose(mps_file_temp);
+ QFile::remove(tempname);
+ tempname.clear();
+ }
+
+ if (written_wpt_mkshort_handle) {
+ mkshort_del_handle(&written_wpt_mkshort_handle);
+ }
+ /* flush the "private" queue of waypoints written */
+ mps_wpt_q_deinit(&written_wpt_head);
+ mps_wpt_q_deinit(&written_route_wpt_head);
+ fin_name.clear();
+}
+
+/*
+ * get characters until and including terminating NULL from mps_file_in
+ * and write into buf.
+ */
+static void
+mps_readstr(gbfile* mps_file, char* buf, size_t sz)
+{
+ int c;
+ buf[sz-1] = 0;
+ while (--sz && (c = gbfgetc(mps_file)) != EOF) {
+ *buf++ = c;
+ if (c == 0) {
+ return;
+ }
+ }
+}
+
+/*
+ * read in from file to check a) valid format b) version of data formatting
+ * MRCB
+ */
+static void
+mps_fileHeader_r(gbfile* mps_file, int* mps_ver)
+{
+ char hdr[100];
+
+ mps_readstr(mps_file, hdr, sizeof(hdr));
+ if (strcmp(hdr, "MsRcd")) {
+ fatal(MYNAME ": This doesn't look like a mapsource file.\n");
+ }
+ /* Read record length of "format details" section */
+ int reclen = gbfgetint32(mps_file);
+ /* Read the "format details" in plus the trailing null */
+ gbfread(hdr, 3, 1, mps_file);
+ if (hdr[0] != 'D') {
+ /* No flag for the "data" section */
+ fatal(MYNAME ": This doesn't look like a mapsource file.\n");
+ }
+ if (hdr[1] == 'd') {
+ *mps_ver = 3;
+ } else if ((hdr[1] > 'd') && (hdr[1] <= 'h')) {
+ *mps_ver = 4;
+ } else if ((hdr[1] > 'h') && (hdr[1] <= 'i')) {
+ *mps_ver = 5;
+ } else {
+ fatal(MYNAME ": Unsupported version of mapsource file.\n");
+ }
+ /* Skip reliably over the "format details" section */
+ gbfseek(mps_file, reclen+1-3, SEEK_CUR);
+ /* Read record length of "program signature" section */
+ reclen = gbfgetint32(mps_file);
+ /* Skip reliably over the "program signature" section */
+ if (reclen >= 0) {
+ gbfseek(mps_file, reclen+1, SEEK_CUR);
+ }
+}
+
+/*
+ * write out to file
+ * MRCB
+ */
+static void
+mps_fileHeader_w(gbfile* mps_file, int mps_ver)
+{
+ char hdr[100];
+
+ strcpy(hdr, "MsRc");
+ gbfwrite(hdr, 4, 1, mps_file);
+
+ /* Between versions 3 & 5 this value is 'd', but might change in the future */
+ strcpy(hdr, "d");
+ gbfwrite(hdr, 2, 1, mps_file); /* include trailing NULL char */
+
+ /* Start of a "Data" section */
+ hdr[0] = 'D';
+ /* if (mps_ver == 3) */
+ hdr[1] = 'd'; /* equates to V3.02 */
+ if (mps_ver == 4) {
+ hdr[1] = 'g'; /* equates to V4.06 */
+ }
+ if (mps_ver == 5) {
+ hdr[1] = 'i'; /* equates to V5.0 */
+ }
+ hdr[2] = 0;
+
+ int reclen = 2; /* this is 3 byte record */
+ gbfputint32(reclen, mps_file);
+ gbfwrite(hdr, 3, 1, mps_file); /* reclen + 1 */
+
+ hdr[0] = 'A';
+ /* if (mps_ver == 3) */
+ hdr[1] = 0x2E;
+ hdr[2] = 0x01; /* equates to V3.02 */
+ hdr[3] = 'S';
+ hdr[4] = 'Q';
+ hdr[5] = 'A';
+ hdr[6] = 0;
+ strcpy(hdr+7,"Oct 20 1999");
+ strcpy(hdr+19,"12:50:33");
+ if (mps_ver == 4) {
+ hdr[1] = (char) 0x96; /* equates to V4.06 */
+ strcpy(hdr+7,"Oct 22 2001");
+ strcpy(hdr+19,"15:45:33");
+ }
+ if (mps_ver == 5) {
+ hdr[1] = (char) 0xF4; /* equates to V5.0 */
+ strcpy(hdr+7,"Jul 3 2003");
+ strcpy(hdr+19,"08:35:33");
+ }
+
+ reclen = 27; /* pre measured! */
+ gbfputint32(reclen, mps_file);
+ gbfwrite(hdr, 28, 1, mps_file); /* reclen + 1 - can't use this as reclen may be wrongendian now */
+}
+
+/*
+ * read in from file a map segment record
+ * MRCB
+ */
+static void
+mps_mapsegment_r(gbfile* mps_file, int mps_ver)
+{
+ int reclen;
+
+ (void)mps_ver;
+
+#if 0
+ /* At the moment we're not doing anything with map segments, but here's the template code as if we were */
+ char hdr[100];
+ gbfread(&CDid, 4, 1, mps_file);
+ reclen = le_read32(&CDid);
+
+ gbfread(&CDSegmentid, 4, 1, mps_file);
+ reclen = le_read32(&CDSegmentid);
+
+ mps_readstr(mps_file, CDName, sizeof(CDName));
+ mps_readstr(mps_file, CDSegmentName, sizeof(CDSegmentName));
+ mps_readstr(mps_file, CDAreaName, sizeof(CDAreaName));
+
+ gbfread(hdr, 4, 1, mps_file); /* trailing long value */
+#endif
+
+ gbfseek(mps_file, -5, SEEK_CUR);
+ reclen = gbfgetint32(mps_file);
+ if (reclen >= 0) {
+ gbfseek(mps_file, reclen+1, SEEK_CUR);
+ }
+}
+
+
+/*
+ * read in from file a mapsetname record
+ * there should always be one of these at the end of the file
+ * MRCB
+ */
+static void
+mps_mapsetname_r(gbfile* mps_file, int mps_ver)
+{
+ (void)mps_ver;
+
+ /* At the moment we're not doing anything with mapsetnames, but here's the template code as if we were
+ char hdr[100];
+ mps_readstr(mps_file, hdr, sizeof(hdr));
+ char mapsetnamename[very large number?];
+ strcpy(mapsetnamename,hdr);
+ char mapsetnameAutonameFlag;
+ gbfread(&mapsetnameAutonameFlag, 1, 1, mps_file); */
+
+ gbfseek(mps_file, -5, SEEK_CUR);
+ int reclen = gbfgetint32(mps_file);
+ gbfseek(mps_file, reclen+1, SEEK_CUR);
+}
+
+
+/*
+ * write out to file a mapsetname record
+ * there should always be one of these at the end of the file
+ * MRCB
+ */
+static void
+mps_mapsetname_w(gbfile* mps_file, int mps_ver)
+{
+ char hdr[100];
+
+ (void)mps_ver;
+
+ hdr[0] = 'V'; /* mapsetname start of record indicator */
+ hdr[1] = 0; /* zero length null terminated string */
+ hdr[2] = 1; /* mapsetname autoname flag set to DO autoname */
+ int reclen = 2; /* three bytes of the V record */
+ gbfputint32(reclen, mps_file);
+ gbfwrite(hdr, 3, 1, mps_file); /* reclen + 1 */
+}
+
+
+/*
+ * read in from file a waypoint record
+ * MRCB
+ */
+static void
+mps_waypoint_r(gbfile* mps_file, int mps_ver, Waypoint** wpt, unsigned int* mpsclass)
+{
+ char tbuf[100];
+ char wptname[MPSNAMEBUFFERLEN];
+ double mps_altitude = unknown_alt;
+ double mps_proximity = unknown_alt;
+ double mps_depth = unknown_alt;
+
+ auto* thisWaypoint = new Waypoint;
+ *wpt = thisWaypoint;
+
+ mps_readstr(mps_file, wptname, sizeof(wptname));
+
+ (*mpsclass) = gbfgetint32(mps_file); /* class */
+ mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* country */
+
+ gbfread(tbuf,17, 1, mps_file); /* subclass data (17) */
+
+ if ((mps_ver == 4) || (mps_ver == 5)) {
+ gbfread(tbuf, 5, 1, mps_file); /* additional subclass data (1) & terminator? (4) */
+ }
+
+ int lat = gbfgetint32(mps_file);
+ int lon = gbfgetint32(mps_file);
+
+ if (gbfgetc(mps_file) == 1) { /* altitude validity */
+ mps_altitude = gbfgetdbl(mps_file);
+ } else {
+ mps_altitude = unknown_alt;
+ gbfseek(mps_file, 8, SEEK_CUR);
+ }
+
+ QString wptdesc = gbfgetcstr(mps_file);
+
+ if (gbfgetc(mps_file) == 1) { /* proximity validity */
+ mps_proximity = gbfgetdbl(mps_file);
+ } else {
+ mps_proximity = unknown_alt;
+ gbfseek(mps_file, 8, SEEK_CUR);
+ }
+
+ (void) gbfgetint32(mps_file); /* display flag */
+ (void) gbfgetint32(mps_file); /* colour */
+ int icon = gbfgetint32(mps_file); /* display symbol */
+
+ mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* city */
+ mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* state */
+ mps_readstr(mps_file, tbuf, sizeof(tbuf)); /*facility */
+
+ gbfread(tbuf, 1, 1, mps_file); /* unknown */
+
+ if (gbfgetc(mps_file) == 1) { /* depth validity */
+ mps_depth = gbfgetdbl(mps_file);
+ } else {
+ mps_depth = unknown_alt;
+ (void) gbfseek(mps_file, 8, SEEK_CUR);
+ }
+
+ if ((mps_ver == 4) || (mps_ver == 5)) {
+ gbfread(tbuf, 6, 1, mps_file); /* unknown */
+ thisWaypoint->notes = gbfgetcstr(mps_file);
+ } else {
+ gbfread(tbuf, 2, 1, mps_file); /* unknown */
+ }
+
+ thisWaypoint->shortname = wptname;
+ thisWaypoint->description = wptdesc;
+ thisWaypoint->latitude = GPS_Math_Semi_To_Deg(lat);
+ thisWaypoint->longitude = GPS_Math_Semi_To_Deg(lon);
+ thisWaypoint->altitude = mps_altitude;
+ if (mps_proximity != unknown_alt) {
+ WAYPT_SET(thisWaypoint, proximity, mps_proximity);
+ }
+ if (mps_depth != unknown_alt) {
+ WAYPT_SET(thisWaypoint, depth, mps_depth);
+ }
+
+ /* might need to change this to handle version dependent icon handling */
+ thisWaypoint->icon_descr = gt_find_desc_from_icon_number(icon, MAPSOURCE);
+}
+
+/*
+ * write out to file a waypoint record
+ * MRCB
+ */
+static void
+mps_waypoint_w(gbfile* mps_file, int mps_ver, const Waypoint* wpt, const bool isRouteWpt)
+{
+ char zbuf[25];
+ char ffbuf[25];
+ int display = 1;
+ int colour = 0; /* (unknown colour) black is 1, white is 16 */
+
+ double mps_altitude = wpt->altitude;
+ double mps_proximity = (mpsuseprox ? WAYPT_GET(wpt, proximity, unknown_alt) : unknown_alt);
+ double mps_depth = unknown_alt;
+
+ int lat = GPS_Math_Deg_To_Semi(wpt->latitude);
+ int lon = GPS_Math_Deg_To_Semi(wpt->longitude);
+ if (WAYPT_HAS(wpt, depth) && mpsusedepth) {
+ mps_depth = wpt->depth;
+ }
+ QString src;
+ if (!wpt->description.isEmpty()) {
+ src = wpt->description;
+ }
+ if (!wpt->notes.isEmpty()) {
+ src = wpt->notes;
+ }
+ QString ident = global_opts.synthesize_shortnames ?
+ mkshort(mkshort_handle, src) :
+ CSTRc(wpt->shortname);
+
+ memset(zbuf, 0, sizeof(zbuf));
+ memset(ffbuf, 0xff, sizeof(ffbuf));
+
+ /* might need to change this to handle version dependent icon handling */
+ int icon = gt_find_icon_number_from_desc(wpt->icon_descr, MAPSOURCE);
+ if (get_cache_icon(wpt)) {
+ icon = gt_find_icon_number_from_desc(get_cache_icon(wpt), MAPSOURCE);
+ }
+
+ icon = mps_converted_icon_number(icon, mps_ver, MAPSOURCE);
+
+ /* two NULL (0x0) bytes at end of each string */
+ char* ascii_description = xstrdup(wpt->description);
+ int reclen = ident.length() + strlen(ascii_description) + 2;
+ if ((mps_ver == 4) || (mps_ver == 5)) {
+ /* v4.06 & V5.0*/
+ reclen += 85; /* "W" (1) + strlen(name) + NULL (1) + class(4) + country(sz) +
+ subclass(18) + unknown(4) + lat(4) + lon(4) + alt(9) + strlen(desc)
+ + NULL (1) + prox(9) + display(4) + colour(4) + symbol(4) + city(sz) +
+ state(sz) + facility(sz) + unknown2(1) + depth(9) + unknown3(7) */
+ /* -1 as reclen is interpreted from zero meaning a reclength of one */
+ if (!wpt->notes.isEmpty()) {
+ reclen += strlen(CSTRc(wpt->notes));
+ }
+ } else {
+ /* v3.02 */
+ reclen += 75; /* "W" (1) + strlen(name) + NULL (1) + + class(4) + country(sz) +
+ subclass(17) + lat(4) + lon(4) + alt(9) + strlen(desc) +
+ NULL (1) + prox(9) + display(4) +
+ colour(4) + symbol(4) + city(sz) + state(sz) + facility(sz) +
+ unknown2(1) + depth(9) + unknown3(2) */
+ /* -1 as reclen is interpreted from zero meaning a reclength of one */
+ }
+
+ gbfputint32(reclen, mps_file);
+ gbfwrite("W", 1, 1, mps_file);
+ gbfputs(ident, mps_file);
+ gbfwrite(zbuf, 1, 1, mps_file); /* NULL termination to ident */
+
+ if (isRouteWpt) {
+ zbuf[0] = (char)MPSHIDDENROUTEWPTCLASS;
+ } else {
+ zbuf[0] = (char)MPSDEFAULTWPTCLASS;
+ }
+ gbfwrite(zbuf, 4, 1, mps_file); /* class */
+
+ zbuf[0]=0;
+ gbfwrite(zbuf, 1, 1, mps_file); /* country empty string */
+
+ if ((mps_ver == 4) || (mps_ver == 5)) {
+ gbfwrite(zbuf, 4, 1, mps_file); /* subclass part 1 */
+ gbfwrite(ffbuf, 12, 1, mps_file); /* subclass part 2 */
+ gbfwrite(zbuf, 2, 1, mps_file); /* subclass part 3 */
+ gbfwrite(ffbuf, 4, 1, mps_file); /* unknown */
+ } else {
+ gbfwrite(zbuf, 8, 1, mps_file);
+ gbfwrite(ffbuf, 8, 1, mps_file);
+ gbfwrite(zbuf, 1, 1, mps_file);
+ }
+
+ gbfputint32(lat, mps_file);
+ gbfputint32(lon, mps_file);
+
+ if (mps_altitude == unknown_alt) {
+ gbfwrite(zbuf, 9, 1, mps_file);
+ } else {
+ gbfputc(1, mps_file);
+ gbfputdbl(mps_altitude, mps_file);
+ }
+ if (!wpt->description.isEmpty()) {
+ gbfputs(ascii_description, mps_file);
+ }
+ gbfwrite(zbuf, 1, 1, mps_file); /* NULL termination */
+ xfree(ascii_description);
+ ascii_description = nullptr;
+
+ if (mps_proximity == unknown_alt) {
+ gbfwrite(zbuf, 9, 1, mps_file);
+ } else {
+ gbfputc(1, mps_file);
+ gbfputdbl(mps_proximity, mps_file);
+ }
+
+ gbfputint32(display, mps_file); /* Show waypoint w/ name */
+ gbfputint32(colour, mps_file);
+ gbfputint32(icon, mps_file);
+
+ gbfwrite(zbuf, 3, 1, mps_file); /* city, state, facility */
+
+ gbfwrite(zbuf, 1, 1, mps_file); /* unknown */
+
+ if (mps_depth == unknown_alt) {
+ gbfwrite(zbuf, 9, 1, mps_file);
+ } else {
+ gbfputc(1, mps_file);
+ gbfputdbl(mps_depth, mps_file);
+ }
+
+ gbfwrite(zbuf, 2, 1, mps_file); /* unknown */
+ if ((mps_ver == 4) || (mps_ver == 5)) {
+ gbfwrite(zbuf, 4, 1, mps_file); /* unknown */
+ if (!wpt->notes.isEmpty()) {
+ gbfputs(wpt->notes, mps_file);
+ }
+ gbfwrite(zbuf, 1, 1, mps_file); /* string termination */
+ }
+}
+
+/*
+ * wrapper to include the mps_ver_out information
+ * A waypoint is only written if it hasn't been written before
+ * based on it shortname alone
+ *
+ */
+static void
+mps_waypoint_w_unique_wrapper(const Waypoint* wpt)
+{
+ /* Search for this waypoint in the ones already written */
+ Waypoint* wptfound = mps_find_wpt_q_by_name(&written_wpt_head, CSTRc(wpt->shortname));
+ /* is the next line necessary? Assumes we know who's called us and in what order */
+ if (wptfound == nullptr) {
+ wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, CSTRc(wpt->shortname));
+ }
+
+ /* if this waypoint hasn't been written then it is okay to do so */
+ if (wptfound == nullptr) {
+ mps_waypoint_w(mps_file_out, mps_ver_out, wpt, false);
+
+ /* ensure we record in our "private" queue what has been
+ written so that we don't write it again */
+ mps_wpt_q_add(&written_wpt_head, wpt);
+ }
+}
+
+/*
+ * wrapper to include the mps_ver_out information
+ * A waypoint is only written if it hasn't been written before
+ * based on it shortname alone
+ * Provided as a separate function from above in case we find
+ * have to do other things
+ *
+ */
+static void
+mps_route_wpt_w_unique_wrapper(const Waypoint* wpt)
+{
+ /* Search for this waypoint in the ones already written */
+ Waypoint* wptfound = mps_find_wpt_q_by_name(&written_wpt_head, CSTRc(wpt->shortname));
+ if (wptfound == nullptr)
+ /* so, not a real wpt, so must check route wpts already written as reals */
+ {
+ wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, CSTRc(wpt->shortname));
+ }
+
+ /* if this waypoint hasn't been written then it is okay to do so
+ but assume it is only required for the route
+ */
+ if (wptfound == nullptr) {
+ /* Although we haven't written one out, this might still be a "real" waypoint
+ If so, we need to write it out now accordingly */
+ wptfound = find_waypt_by_name(wpt->shortname);
+
+ if (wptfound == nullptr) {
+ /* well, we tried to find: it wasn't written and isn't a real waypoint */
+ mps_waypoint_w(mps_file_out, mps_ver_out, wpt, true);
+ mps_wpt_q_add(&written_route_wpt_head, wpt);
+ } else {
+ mps_waypoint_w(mps_file_out, mps_ver_out, wpt, false);
+ /* Simulated real user waypoint */
+ mps_wpt_q_add(&written_wpt_head, wpt);
+ }
+ }
+}
+#if 0
+/*
+ * wrapper to include the mps_ver_out information
+ * This one always writes a waypoint. If it has been written before
+ * then generate a unique name before writing
+ *
+ */
+static void
+mps_waypoint_w_uniqloc_wrapper(Waypoint* wpt)
+{
+ Waypoint* wptfound = NULL;
+ char* newName;
+
+ /* Search for this waypoint in the ones already written */
+ wptfound = mps_find_wpt_q_by_name(&written_wpt_head, wpt->shortname);
+ /* is the next line necessary? Assumes we know who's called us and in what order */
+ if (wptfound == NULL) {
+ wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, wpt->shortname);
+ }
+
+ if (wptfound != NULL) {
+ /* check if this is the same waypoint by looking at the lat lon
+ not ideal, but better then having two same named waypoints
+ that kills MapSource. If it is the same then don't bother
+ adding it in. If it isn't, then rename it
+ */
+ if (((wpt->latitude - wptfound->latitude) != 0) ||
+ ((wpt->longitude - wptfound->longitude) != 0)) {
+ /* Not the same lat lon, so rename and add */
+ newName = mkshort(written_wpt_mkshort_handle, wpt->shortname);
+ wptfound = new Waypoint(*wpt);
+ xfree(wptfound->shortname);
+ wptfound->shortname = newName;
+ mps_waypoint_w(mps_file_out, mps_ver_out, wptfound, false);
+ mps_wpt_q_add(&written_wpt_head, wpt);
+ }
+ } else {
+ mps_waypoint_w(mps_file_out, mps_ver_out, wpt, false);
+ /* ensure we record in out "private" queue what has been
+ written so that we don't write it again */
+ mps_wpt_q_add(&written_wpt_head, wpt);
+ }
+}
+#endif
+
+/*
+ * read in from file a route record
+ * MRCB
+ */
+static void
+mps_route_r(gbfile* mps_file, int mps_ver, route_head** rte)
+{
+ char tbuf[100];
+ char wptname[MPSNAMEBUFFERLEN];
+ int lat = 0;
+ int lon = 0;
+ char rte_autoname;
+ int interlinkStepCount;
+ unsigned int mpsclass;
+
+ route_head* rte_head;
+ int rte_count;
+
+ Waypoint* thisWaypoint;
+ Waypoint* tempWpt;
+
+ double mps_altitude = unknown_alt;
+ double mps_depth = unknown_alt;
+
+ QString rtename = gbfgetcstr(mps_file);
+#ifdef MPS_DEBUG
+ fprintf(stderr, "mps_route_r: reading route %s\n", rtename);
+#endif
+
+ gbfread(&rte_autoname, 1, 1, mps_file); /* autoname flag */
+
+ gbfread(tbuf, 1, 1, mps_file); /* skip min/max values */
+ if (tbuf[0] == 0) {
+
+ lat = gbfgetint32(mps_file); /* max lat of whole route */
+ lon = gbfgetint32(mps_file); /* max lon of whole route */
+
+ if (gbfgetc(mps_file) == 1) { /* altitude validity */
+ mps_altitude = gbfgetdbl(mps_file);
+ } else {
+ mps_altitude = unknown_alt;
+ gbfseek(mps_file, 8, SEEK_CUR);
+ }
+
+ lat = gbfgetint32(mps_file); /* min lat of whole route */
+ lon = gbfgetint32(mps_file); /* min lon of whole route */
+
+ if (gbfgetc(mps_file) == 1) { /* altitude validity */
+ mps_altitude = gbfgetdbl(mps_file);
+ } else {
+ mps_altitude = unknown_alt;
+ gbfseek(mps_file, 8, SEEK_CUR);
+ }
+ }
+
+ rte_count = gbfgetint32(mps_file); /* number of waypoints in route */
+
+ /* This might be rather presumptuous, but is it valid in any format to have route with no points? */
+ /* Let's assume not, so if the route count is zero or less, let's get out of here and allow the */
+ /* caller to do any file resync */
+ if (rte_count < 0) {
+ return;
+ }
+
+#ifdef MPS_DEBUG
+ fprintf(stderr, "mps_route_r: route contains %d waypoints\n", rte_count);
+#endif
+
+ rte_head = new route_head;
+ rte_head->rte_name = rtename;
+ route_add_head(rte_head);
+ *rte = rte_head;
+
+ rte_count--; /* need to loop round for one less than the number of waypoints */
+
+ while (rte_count--) {
+
+ mps_readstr(mps_file, wptname, sizeof(wptname));
+#ifdef MPS_DEBUG
+ fprintf(stderr, "mps_route_r: reading route waypoint %s\n", wptname);
+#endif
+
+ mpsclass = gbfgetint32(mps_file); /* class */
+ (void)mpsclass;
+ mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* country */
+
+ if ((mps_ver == 4) || (mps_ver == 5)) {
+ gbfread(tbuf, 22, 1, mps_file); /* subclass data */
+
+ /* This is a bit unpleasant. Routes have a variable length of
+ data (min 22 bytes) terminated by a zero */
+ do {
+ gbfread(tbuf, 1, 1, mps_file);
+ } while (tbuf[0] && !gbfeof(mps_file));
+
+ /* The next thing is the unknown 0x03 0x00 .. 0x00 (18 bytes) */
+ gbfread(tbuf, 18, 1, mps_file);
+ } else {
+ gbfread(tbuf, 17, 1, mps_file); /* subclass data */
+ gbfread(tbuf, 18, 1, mps_file); /* unknown 0x00 0x03 0x00 .. 0x00 */
+ }
+
+ /* link details */
+ interlinkStepCount = gbfgetint32(mps_file); /* NOT always 2, but will assume > 0 */
+
+#ifdef MPS_DEBUG
+ fprintf(stderr, "mps_route_r: interlink steps are %d\n", interlinkStepCount);
+#endif
+
+ /* Basically we're knackered if the step count is less than one since we hard code reading of the */
+ /* first, so if there isn't one, we'd lose sync on the file and read junk */
+ /* Given we've already done some route head allocation, do we return or do we die? It'd be good */
+ /* do some clean up before returning. */
+ if (interlinkStepCount < 1) {
+ /* For RJL - are the following lines correct ? */
+ /* route_free(rte_head);
+ route_del_head(rte_head); */
+ return;
+ }
+
+ /* first end of link */
+ lat = gbfgetint32(mps_file);
+ lon = gbfgetint32(mps_file);
+
+ if (gbfgetc(mps_file) == 1) { /* altitude validity */
+ mps_altitude = gbfgetdbl(mps_file);
+ } else {
+ mps_altitude = unknown_alt;
+ gbfseek(mps_file, 8, SEEK_CUR);
+ }
+
+ /* with MapSource routes, the real waypoint details are held as a separate waypoint, so copy from there
+ if found. With MapSource, one should consider the real waypoint list as definitive */
+ tempWpt = find_waypt_by_name(wptname);
+
+ if (tempWpt != nullptr) {
+ thisWaypoint = new Waypoint(*tempWpt);
+ } else {
+ tempWpt = mps_find_wpt_q_by_name(&read_route_wpt_head, wptname);
+
+ if (tempWpt != nullptr) {
+ thisWaypoint = new Waypoint(*tempWpt);
+ } else {
+ /* should never reach here, but we do need a fallback position */
+#ifdef MPS_DEBUG
+ fprintf(stderr, "mps_route_r: reached the point we never should\n");
+#endif
+ thisWaypoint = new Waypoint;
+ thisWaypoint->shortname = wptname;
+ thisWaypoint->latitude = GPS_Math_Semi_To_Deg(lat);
+ thisWaypoint->longitude = GPS_Math_Semi_To_Deg(lon);
+ thisWaypoint->altitude = mps_altitude;
+ if (mps_depth != unknown_alt) {
+ WAYPT_SET(thisWaypoint, depth, mps_depth);
+ }
+ }
+ }
+
+ route_add_wpt(rte_head, thisWaypoint);
+
+ /* take two off the count since we separately read the start and end parts of the link */
+ /* MRCB 2004/09/15 - NOPE, sorry, this needs to one, since interlink steps can be > 0 */
+ for (int thisInterlinkStep = interlinkStepCount - 1; thisInterlinkStep > 0; thisInterlinkStep--) {
+ /* Could do this by doing a calculation on length of each co-ordinate and just doing one read
+ but doing it this way makes it easier in the future to make use of this data */
+ lat = gbfgetint32(mps_file);
+ lon = gbfgetint32(mps_file);
+
+ if (gbfgetc(mps_file) == 1) { /* altitude validity */
+ mps_altitude = gbfgetdbl(mps_file);
+ } else {
+ mps_altitude = unknown_alt;
+ gbfseek(mps_file, 8, SEEK_CUR);
+ }
+ }
+
+ gbfread(tbuf, 1, 1, mps_file); /* NULL */
+
+ gbfread(tbuf, 4, 1, mps_file); /* link max lat */
+ gbfread(tbuf, 4, 1, mps_file); /* link max lon */
+ gbfread(tbuf, 9, 1, mps_file); /* link max alt validity + alt */
+
+ gbfread(tbuf, 4, 1, mps_file); /* link min lat */
+ gbfread(tbuf, 4, 1, mps_file); /* link min lon */
+ gbfread(tbuf, 9, 1, mps_file); /* link min alt validity + alt */
+
+ } /* while (trk_count--) */
+
+ /* when the loop is done, there's still one waypoint to read with a small trailer */
+ /* all we want is the waypoint name; lat, lon and alt are already set from above */
+ mps_readstr(mps_file, wptname, sizeof(wptname));
+#ifdef MPS_DEBUG
+ fprintf(stderr, "mps_route_r: reading final route waypoint %s\n", wptname);
+#endif
+
+
+ mpsclass = gbfgetint32(mps_file); /* class */
+ mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* country */
+
+ if ((mps_ver == 4) || (mps_ver == 5)) {
+ gbfread(tbuf, 22, 1, mps_file); /* subclass data */
+
+ /* This is a bit unpleasant. Routes have a variable length of
+ data (min 22 bytes) terminated by a zero */
+ do {
+ gbfread(tbuf, 1, 1, mps_file);
+ } while (tbuf[0] && !gbfeof(mps_file));
+
+ /* The next thing is the unknown 0x03 0x00 .. 0x00 (18 bytes) */
+ gbfread(tbuf, 18, 1, mps_file);
+ } else {
+ gbfread(tbuf, 17, 1, mps_file); /* subclass data */
+ gbfread(tbuf, 18, 1, mps_file); /* unknown 0x00 0x03 0x00 .. 0x00 */
+ }
+
+ gbfread(tbuf, 5, 1, mps_file); /* 5 byte trailer */
+ /* with MapSource routes, the real waypoint details are held as a separate waypoint, so copy from there
+ if found because there is more info held in a real waypoint than in its route counterpart,
+ e.g. the display symbol (aka icon)
+ */
+ tempWpt = find_waypt_by_name(wptname);
+
+ if (tempWpt != nullptr) {
+ thisWaypoint = new Waypoint(*tempWpt);
+ } else {
+ tempWpt = mps_find_wpt_q_by_name(&read_route_wpt_head, wptname);
+
+ if (tempWpt != nullptr) {
+ thisWaypoint = new Waypoint(*tempWpt);
+ } else {
+ /* should never reach here, but we do need a fallback position */
+ thisWaypoint = new Waypoint;
+ thisWaypoint->shortname = wptname;
+ thisWaypoint->latitude = GPS_Math_Semi_To_Deg(lat);
+ thisWaypoint->longitude = GPS_Math_Semi_To_Deg(lon);
+ thisWaypoint->altitude = mps_altitude;
+ }
+ }
+
+ route_add_wpt(rte_head, thisWaypoint);
+}
+
+/*
+ * write out to file a route header
+ * MRCB
+ */
+static void
+mps_routehdr_w(gbfile* mps_file, int mps_ver, const route_head* rte)
+{
+ char* rname;
+ char hdr[20];
+ char zbuf[20];
+
+ time_t uniqueValue = 0;
+
+ double maxlat=-90.0;
+ double maxlon=-180.0;
+ double minlat=90.0;
+ double minlon=180.0;
+ double maxalt=unknown_alt;
+ double minalt=-unknown_alt;
+
+ prevRouteWpt = nullptr; /* clear the stateful flag used to know when the start of route wpts happens */
+
+ memset(zbuf, 0, sizeof(zbuf));
+
+ /* total nodes (waypoints) this route */
+ unsigned int rte_datapoints = 0;
+ int allWptNameLengths = 0;
+
+ //if (rte->waypoint_list.next) { /* this test doesn't do what I want i.e test if this is a valid route - treat as a placeholder for now */
+ if (true) {
+ foreach (const Waypoint* testwpt, rte->waypoint_list) {
+ if (rte_datapoints == 0) {
+ uniqueValue = testwpt->GetCreationTime().toTime_t();
+ }
+ if (testwpt->latitude > maxlat) {
+ maxlat = testwpt->latitude;
+ }
+ if (testwpt->latitude < minlat) {
+ minlat = testwpt->latitude;
+ }
+ if (testwpt->longitude > maxlon) {
+ maxlon = testwpt->longitude;
+ }
+ if (testwpt->longitude < minlon) {
+ minlon = testwpt->longitude;
+ }
+ if (testwpt->altitude != unknown_alt) {
+ if ((testwpt->altitude > maxalt) ||
+ (maxalt == unknown_alt)) {
+ maxalt = testwpt->altitude;
+ }
+ if ((testwpt->altitude < minalt) ||
+ (minalt == -unknown_alt)) {
+ minalt = testwpt->altitude;
+ }
+ }
+
+ QString src;
+ if (!testwpt->description.isEmpty()) {
+ src = testwpt->description;
+ }
+ if (!testwpt->notes.isEmpty()) {
+ src = testwpt->notes;
+ }
+ QString ident = global_opts.synthesize_shortnames ?
+ mkshort(mkshort_handle, src) :
+ CSTRc(testwpt->shortname);
+ allWptNameLengths += ident.length() + 1;
+
+ rte_datapoints++;
+ }
+
+ if (uniqueValue == 0) {
+ uniqueValue = current_time().toTime_t();
+ }
+
+ /* route name */
+ if (rte->rte_name.isEmpty()) {
+ sprintf(hdr, "Route%04x", (unsigned) uniqueValue);
+ rname = xstrdup(hdr);
+ } else {
+ rname = xstrdup(rte->rte_name);
+ }
+
+ int rname_len = strlen(rname);
+ unsigned int reclen = rname_len + 42; /* "T" (1) + strlen(tname) + NULL (1) + autoname flag (2) +
+ route lat lon max (2x4) + route max alt (9) +
+ route lat lon min (2x4) + route min alt (9) +
+ num route datapoints value (4) */
+
+ /* V3 - each waypoint: waypoint name + NULL (1) + class (4) + country + NULL (1) +
+ subclass (17) + unknown (18) */
+ /* V4,5 - each waypoint: waypoint name + NULL (1) + class (4) + country + NULL (1) +
+ subclass (18) + unknown (4) + unknown (19) */
+ /* V* - each route link: 0x00000002 (4) + end 1 lat (4) + end 1 lon (4) + end 1 alt (9) +
+ end 2 lat (4) + end 2 lon (4) + end 2 alt (9) + NULL (1) +
+ link max lat (4) + link max lon (4) + link max alt (9) +
+ link min lat (4) + link min lon (4) + link min alt (9) */
+
+ if ((mps_ver == 4) || (mps_ver == 5)) {
+ reclen += allWptNameLengths + rte_datapoints * 46 +
+ (rte_datapoints - 1) * 73 + 4; /* link details plus overall trailing bytes */
+ } else {
+ reclen += allWptNameLengths + rte_datapoints * 40 +
+ (rte_datapoints - 1) * 73 + 4; /* link details plus overall trailing bytes */
+ }
+
+ gbfputint32(reclen, mps_file);
+ gbfputc('R', mps_file);
+ gbfwrite(rname, 1, rname_len, mps_file);
+
+ xfree(rname);
+
+ hdr[0] = 0; /* NULL of string termination */
+ hdr[1] = 0; /* don't autoname */
+ hdr[2] = 0; /* MSB of don't autoname */
+ gbfwrite(hdr, 3, 1, mps_file); /* NULL string terminator + route autoname flag */
+
+ int lat = GPS_Math_Deg_To_Semi(maxlat);
+ int lon = GPS_Math_Deg_To_Semi(maxlon);
+
+ gbfputint32(lat, mps_file);
+ gbfputint32(lon, mps_file);
+
+ if (maxalt == unknown_alt) {
+ gbfwrite(zbuf, 9, 1, mps_file);
+ } else {
+ gbfputc(1, mps_file);
+ gbfputdbl(maxalt, mps_file);
+ }
+
+ lat = GPS_Math_Deg_To_Semi(minlat);
+ lon = GPS_Math_Deg_To_Semi(minlon);
+
+ gbfputint32(lat, mps_file);
+ gbfputint32(lon, mps_file);
+
+ if (minalt == -unknown_alt) {
+ gbfwrite(zbuf, 9, 1, mps_file);
+ } else {
+ gbfputc(1, mps_file);
+ gbfputdbl(minalt, mps_file);
+ }
+
+ gbfputint32(rte_datapoints, mps_file);
+ }
+}
+
+static void
+mps_routehdr_w_wrapper(const route_head* rte)
+{
+ mps_routehdr_w(mps_file_out, mps_ver_out, rte);
+}
+
+
+/*
+ * write out to file a route datapoint
+ * MRCB
+ */
+static void
+mps_routedatapoint_w(gbfile* mps_file, int mps_ver, const Waypoint* rtewpt)
+{
+ char zbuf[20];
+ char ffbuf[20];
+
+ int maxlat;
+ int maxlon;
+ int minlat;
+ int minlon;
+ double maxalt=unknown_alt;
+ double minalt=-unknown_alt;
+
+ memset(zbuf, 0, sizeof(zbuf));
+ memset(ffbuf, 0xff, sizeof(ffbuf));
+
+ if (prevRouteWpt != nullptr) {
+ /* output the route link details */
+ int reclen = 2;
+ gbfputint32(reclen, mps_file);
+
+ /* output end point 1 */
+ int lat = GPS_Math_Deg_To_Semi(prevRouteWpt->latitude);
+ int lon = GPS_Math_Deg_To_Semi(prevRouteWpt->longitude);
+
+ gbfputint32(lat, mps_file);
+ gbfputint32(lon, mps_file);
+
+ double mps_altitude = prevRouteWpt->altitude;
+ if (mps_altitude == unknown_alt) {
+ gbfwrite(zbuf, 9, 1, mps_file);
+ } else {
+ gbfputc(1, mps_file);
+ gbfputdbl(mps_altitude, mps_file);
+ }
+
+ /* output end point 2 */
+ lat = GPS_Math_Deg_To_Semi(rtewpt->latitude);
+ lon = GPS_Math_Deg_To_Semi(rtewpt->longitude);
+
+ gbfputint32(lat, mps_file);
+ gbfputint32(lon, mps_file);
+
+ mps_altitude = rtewpt->altitude;
+ if (mps_altitude == unknown_alt) {
+ gbfwrite(zbuf, 9, 1, mps_file);
+ } else {
+ gbfputc(1, mps_file);
+ gbfputdbl(mps_altitude, mps_file);
+ }
+
+ if (rtewpt->latitude > prevRouteWpt->latitude) {
+ maxlat = GPS_Math_Deg_To_Semi(rtewpt->latitude);
+ minlat = GPS_Math_Deg_To_Semi(prevRouteWpt->latitude);
+ } else {
+ minlat = GPS_Math_Deg_To_Semi(rtewpt->latitude);
+ maxlat = GPS_Math_Deg_To_Semi(prevRouteWpt->latitude);
+ }
+
+ if (rtewpt->longitude > prevRouteWpt->longitude) {
+ maxlon = GPS_Math_Deg_To_Semi(rtewpt->longitude);
+ minlon = GPS_Math_Deg_To_Semi(prevRouteWpt->longitude);
+ } else {
+ minlon = GPS_Math_Deg_To_Semi(rtewpt->longitude);
+ maxlon = GPS_Math_Deg_To_Semi(prevRouteWpt->longitude);
+ }
+
+ if (rtewpt->altitude != unknown_alt) {
+ maxalt = rtewpt->altitude;
+ }
+ if (rtewpt->altitude != unknown_alt) {
+ minalt = rtewpt->altitude;
+ }
+ if (prevRouteWpt->altitude != unknown_alt) {
+ if ((prevRouteWpt->altitude > maxalt) ||
+ (maxalt == unknown_alt)) {
+ maxalt = prevRouteWpt->altitude;
+ }
+ if ((prevRouteWpt->altitude < minalt) ||
+ (minalt == -unknown_alt)) {
+ minalt = prevRouteWpt->altitude;
+ }
+ }
+
+ gbfwrite(zbuf, 1, 1, mps_file);
+
+ /* output max coords of the link */
+ gbfputint32(maxlat, mps_file);
+ gbfputint32(maxlon, mps_file);
+
+ if (maxalt == unknown_alt) {
+ gbfwrite(zbuf, 9, 1, mps_file);
+ } else {
+ gbfputc(1, mps_file);
+ gbfputdbl(maxalt, mps_file);
+ }
+
+ /* output min coords of the link */
+ gbfputint32(minlat, mps_file);
+ gbfputint32(minlon, mps_file);
+
+ if (minalt == -unknown_alt) {
+ gbfwrite(zbuf, 9, 1, mps_file);
+ } else {
+ gbfputc(1, mps_file);
+ gbfputdbl(minalt, mps_file);
+ }
+
+ }
+
+ QString src;
+ if (!rtewpt->description.isEmpty()) {
+ src = rtewpt->description;
+ }
+ if (!rtewpt->notes.isEmpty()) {
+ src = rtewpt->notes;
+ }
+ QString ident = global_opts.synthesize_shortnames ?
+ mkshort(mkshort_handle, src) :
+ CSTRc(rtewpt->shortname);
+
+ gbfputs(ident, mps_file);
+ gbfwrite(zbuf, 1, 1, mps_file); /* NULL termination to ident */
+
+ Waypoint* wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, ident);
+ if (wptfound != nullptr) {
+ zbuf[0] = (char)MPSHIDDENROUTEWPTCLASS;
+ } else {
+ zbuf[0] = (char)MPSDEFAULTWPTCLASS;
+ }
+ gbfwrite(zbuf, 4, 1, mps_file); /* class */
+
+ zbuf[0]=0;
+ gbfwrite(zbuf, 1, 1, mps_file); /* country - i.e. empty string */
+
+ if ((mps_ver == 4) || (mps_ver == 5)) {
+ gbfwrite(zbuf, 4, 1, mps_file); /* subclass part 1 */
+ gbfwrite(ffbuf, 12, 1, mps_file); /* subclass part 2 */
+ gbfwrite(zbuf, 2, 1, mps_file); /* subclass part 3 */
+ gbfwrite(ffbuf, 4, 1, mps_file); /* unknown */
+
+ gbfwrite(zbuf, 1, 1, mps_file);
+ gbfputc(3, mps_file);
+ gbfwrite(zbuf, 17, 1, mps_file);
+ } else {
+ gbfwrite(zbuf, 8, 1, mps_file); /* subclass part 1 */
+ gbfwrite(ffbuf, 8, 1, mps_file); /* subclass part 2 */
+ gbfwrite(zbuf, 1, 1, mps_file); /* subclass part 3 */
+
+ /* unknown */
+ gbfwrite(zbuf, 1, 1, mps_file);
+ gbfputc(3, mps_file);
+ gbfwrite(zbuf, 16, 1, mps_file);
+ }
+
+ prevRouteWpt = rtewpt;
+}
+
+static void
+mps_routedatapoint_w_wrapper(const Waypoint* rte)
+{
+ mps_routedatapoint_w(mps_file_out, mps_ver_out, rte);
+}
+
+
+/*
+ * write out to file a route trailer
+ * MRCB
+ */
+static void
+mps_routetrlr_w(gbfile* mps_file, int mps_ver, const route_head* /* rte */)
+{
+ char hdr[2];
+ int value = 0;
+
+ (void)mps_ver;
+ hdr[0] = 1;
+
+ //if (rte->waypoint_list.next) { /* this test doesn't do what I want i.e test if this is a valid route - treat as a placeholder for now */
+ if (true) {
+ gbfwrite(&value, 4, 1, mps_file);
+ gbfwrite(hdr, 1, 1, mps_file);
+ }
+}
+
+static void
+mps_routetrlr_w_wrapper(const route_head* rte)
+{
+ mps_routetrlr_w(mps_file_out, mps_ver_out, rte);
+}
+
+
+/*
+ * read in from file a track record
+ * MRCB
+ */
+static void
+mps_track_r(gbfile* mps_file, int mps_ver, route_head** trk)
+{
+ int lat;
+ int lon;
+
+ int dateTime = 0;
+ route_head* track_head;
+ int trk_count;
+
+ Waypoint* thisWaypoint;
+ double mps_altitude = unknown_alt;
+ double mps_depth = unknown_alt;
+
+ (void)mps_ver;
+
+ QString trkname = gbfgetcstr(mps_file);
+#ifdef MPS_DEBUG
+ fprintf(stderr, "mps_track_r: reading track %s\n", trkname);
+#endif
+
+ (void) gbfgetc(mps_file); /* display flag */
+ (void) gbfgetint32(mps_file); /* colour */
+
+ trk_count = gbfgetint32(mps_file); /* number of datapoints in tracklog */
+
+ /* I don't know, but perhaps it's valid to have a track with no waypoints */
+ /* Seems dumb, but truth is stranger than fiction. Of course, it could be */
+ /* that there are more than MAXINT / 2 waypoints, yeah sure */
+ /* Allow the caller the perform the file resync caused by bombing out early */
+ if (trk_count < 0) {
+ return;
+ }
+#ifdef MPS_DEBUG
+ fprintf(stderr, "mps_track_r: there are %d track waypoints\n", trk_count);
+#endif
+
+ track_head = new route_head;
+ track_head->rte_name = trkname;
+ track_add_head(track_head);
+ *trk = track_head;
+
+ while (trk_count--) {
+
+ lat = gbfgetint32(mps_file);
+ lon = gbfgetint32(mps_file);
+
+ if (gbfgetc(mps_file) == 1) { /* altitude validity */
+ mps_altitude = gbfgetdbl(mps_file);
+ } else {
+ mps_altitude = unknown_alt;
+ gbfseek(mps_file, 8, SEEK_CUR);
+ }
+
+ if (gbfgetc(mps_file) == 1) { /* date/time validity */
+ dateTime = gbfgetint32(mps_file);
+ } else {
+ (void) gbfgetint32(mps_file);
+ }
+
+ if (gbfgetc(mps_file) == 1) { /* depth validity */
+ mps_depth = gbfgetdbl(mps_file);
+ } else {
+ mps_depth = unknown_alt;
+ gbfseek(mps_file, 8, SEEK_CUR);
+ }
+
+ thisWaypoint = new Waypoint;
+ thisWaypoint->latitude = GPS_Math_Semi_To_Deg(lat);
+ thisWaypoint->longitude = GPS_Math_Semi_To_Deg(lon);
+ thisWaypoint->SetCreationTime(dateTime);
+ thisWaypoint->altitude = mps_altitude;
+ if (mps_depth != unknown_alt) {
+ WAYPT_SET(thisWaypoint, depth, mps_depth);
+ }
+ track_add_wpt(track_head, thisWaypoint);
+
+ } /* while (trk_count--) */
+
+
+}
+
+/*
+ * write out to file a tracklog header
+ * MRCB
+ */
+static void
+mps_trackhdr_w(gbfile* mps_file, int mps_ver, const route_head* trk)
+{
+ unsigned int colour = 0; /* unknown colour */
+ char* tname;
+ char hdr[20];
+ time_t uniqueValue = 0;
+
+ (void)mps_ver;
+
+ /* total nodes (waypoints) this track */
+ unsigned int trk_datapoints = 0;
+ //if (trk->waypoint_list.next) { /* this test doesn't do what I want i.e test if this is a valid track - treat as a placeholder for now */
+ if (true) {
+ foreach (const Waypoint* testwpt, trk->waypoint_list) {
+ if (trk_datapoints == 0) {
+ uniqueValue = testwpt->GetCreationTime().toTime_t();
+ }
+ trk_datapoints++;
+ }
+
+ if (uniqueValue == 0) {
+ uniqueValue = current_time().toTime_t();
+ }
+
+ /* track name */
+ if (trk->rte_name.isEmpty()) {
+ sprintf(hdr, "Track%04x", (unsigned) uniqueValue);
+ tname = xstrdup(hdr);
+ } else {
+ tname = xstrdup(trk->rte_name);
+ }
+
+ int tname_len = strlen(tname);
+ unsigned int reclen = tname_len + 11; /* "T" (1) + strlen(tname) + NULL (1) + display flag (1) + colour (4) +
+ num track datapoints value (4) */
+
+ reclen += (trk_datapoints * 31) - 1; /* lat (4) + lon (4) + alt (9) + date (5) + depth (9) ;*/
+ /* -1 is because reclen starts from 0 which means a length of 1 */
+ gbfputint32(reclen, mps_file);
+ gbfputc('T', mps_file);
+ gbfwrite(tname, 1, tname_len, mps_file);
+
+ xfree(tname);
+
+ hdr[0] = 0;
+ hdr[1] = 1;
+ gbfwrite(hdr, 2, 1, mps_file); /* NULL string terminator + display flag */
+
+ gbfputint32(colour, mps_file);
+
+ gbfputint32(trk_datapoints, mps_file);
+ }
+
+}
+
+static void
+mps_trackhdr_w_wrapper(const route_head* trk)
+{
+ mps_trackhdr_w(mps_file_out, mps_ver_out, trk);
+}
+
+
+/*
+ * write out to file a tracklog datapoint
+ * MRCB
+ */
+static void
+mps_trackdatapoint_w(gbfile* mps_file, int mps_ver, const Waypoint* wpt)
+{
+ time_t t = wpt->GetCreationTime().toTime_t();
+ char zbuf[10];
+
+ double mps_altitude = wpt->altitude;
+ double mps_depth = unknown_alt;
+
+ (void)mps_ver;
+
+ int lat = GPS_Math_Deg_To_Semi(wpt->latitude);
+ int lon = GPS_Math_Deg_To_Semi(wpt->longitude);
+ if (WAYPT_HAS(wpt, depth) && mpsusedepth) {
+ mps_depth = wpt->depth;
+ }
+
+ memset(zbuf, 0, sizeof(zbuf));
+
+ gbfputint32(lat, mps_file);
+ gbfputint32(lon, mps_file);
+
+ if (mps_altitude == unknown_alt) {
+ gbfwrite(zbuf, 9, 1, mps_file);
+ } else {
+ gbfputc(1, mps_file);
+ gbfputdbl(mps_altitude, mps_file);
+ }
+
+ if (t > 0) { /* a valid time is assumed to > 0 */
+ gbfputc(1, mps_file);
+ gbfputint32(t, mps_file);
+ } else {
+ gbfwrite(zbuf, 5, 1, mps_file);
+ }
+
+ if (mps_depth == unknown_alt) {
+ gbfwrite(zbuf, 9, 1, mps_file);
+ } else {
+ gbfputc(1, mps_file);
+ gbfputdbl(mps_depth, mps_file);
+ }
+}
+
+static void
+mps_trackdatapoint_w_wrapper(const Waypoint* wpt)
+{
+ mps_trackdatapoint_w(mps_file_out, mps_ver_out, wpt);
+}
+
+
+static void
+mps_read()
+{
+ Waypoint* wpt;
+ route_head* rte;
+ route_head* trk;
+
+ char recType;
+ int reclen;
+ int morework;
+ unsigned int mpsWptClass;
+ long mpsFileInPos;
+
+ mps_ver_in = 0; /* although initialised at declaration, what happens if there are two mapsource
+ input files? */
+ mps_fileHeader_r(mps_file_in, &mps_ver_in);
+
+#ifdef DUMP_ICON_TABLE
+ printf("static icon_mapping_t garmin_icon_table[] = {\n");
+#endif
+
+ morework = 1;
+ while (morework && !gbfeof(mps_file_in)) {
+
+ /* Read record length of next section */
+ reclen = gbfgetint32(mps_file_in);
+
+ if (reclen < 0) {
+ fatal(MYNAME ": a record length read from the input file is invalid. \nEither the file is corrupt or unsupported.\n");
+ }
+
+ /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
+ gbfread(&recType, 1, 1, mps_file_in);
+ mpsFileInPos = gbftell(mps_file_in);
+ switch (recType) {
+ case 'W':
+ /* Waypoint record */
+ /* With routes, we need the waypoint info that reveals, for example, the symbol type */
+ mps_waypoint_r(mps_file_in, mps_ver_in, &wpt, &mpsWptClass);
+
+#ifdef MPS_DEBUG
+ fprintf(stderr,"Read a waypoint - %s\n", wpt->shortname);
+#endif
+
+ if (gbftell(mps_file_in) != mpsFileInPos + reclen) {
+ /* should junk this record and not save it since we're out of sync with the file */
+ /* Should and how do we warn the user? */
+#ifdef MPS_DEBUG
+ fprintf(stderr,"Lost sync with the file reading waypoint - %s\n", wpt->shortname);
+#endif
+ gbfseek(mps_file_in, mpsFileInPos + reclen, SEEK_SET);
+ delete wpt;
+ } else {
+ /* only add to the "real" list if a "user" waypoint otherwise add to the private list */
+ if (mpsWptClass == MPSDEFAULTWPTCLASS) {
+ waypt_add(wpt);
+ } else {
+ mps_wpt_q_add(&read_route_wpt_head, wpt);
+ delete wpt;
+ }
+#ifdef DUMP_ICON_TABLE
+ printf("\t{ %4u, \"%s\" },\n", icon, wpt->shortname);
+#endif
+ }
+ break;
+
+ case 'R':
+ /* Route record */
+ mps_route_r(mps_file_in, mps_ver_in, &rte);
+ if (gbftell(mps_file_in) != mpsFileInPos + reclen) {
+ /* should junk this record and not save it since we're out of sync with the file */
+ /* Should and how do we warn the user? */
+#ifdef MPS_DEBUG
+ fprintf(stderr,"Lost sync with the file reading route - %s\n", rte->rte_name);
+#endif
+ gbfseek(mps_file_in, mpsFileInPos + reclen, SEEK_SET);
+ }
+ break;
+
+ case 'T':
+ /* Track record */
+ mps_track_r(mps_file_in, mps_ver_in, &trk);
+ if (gbftell(mps_file_in) != mpsFileInPos + reclen) {
+ /* should junk this record and not save it since we're out of sync with the file */
+ /* Should and how do we warn the user? */
+#ifdef MPS_DEBUG
+ fprintf(stderr,"Lost sync with the file reading track - %s\n", trk->rte_name);
+#endif
+ gbfseek(mps_file_in, mpsFileInPos + reclen, SEEK_SET);
+ }
+ break;
+
+ case 'L':
+ /* Map segment record */
+ mps_mapsegment_r(mps_file_in, mps_ver_in);
+ if (gbftell(mps_file_in) != mpsFileInPos + reclen) {
+ /* should junk this record and not save it since we're out of sync with the file */
+ /* Should and how do we warn the user? */
+ gbfseek(mps_file_in, mpsFileInPos + reclen, SEEK_SET);
+ }
+ break;
+
+ case 'V':
+ /* Mapset record */
+ mps_mapsetname_r(mps_file_in, mps_ver_in);
+ /* Last record in the file */
+ morework = 0;
+ break;
+ default:
+ /* Unknown record type. Skip over it. */
+ gbfseek(mps_file_in, reclen, SEEK_CUR);
+ }
+
+ } /* while (!gbfeof(mps_file_in)) */
+
+#ifdef DUMP_ICON_TABLE
+ printf("\t{ -1, NULL },\n");
+ printf("};\n");
+#endif
+
+
+}
+
+static void
+mps_write()
+{
+ Waypoint* wpt;
+ route_head* rte;
+ route_head* trk;
+
+ char recType = -1;
+ int reclen;
+ /* TODO: This kills a compiler warning but I'm not sure it's right */
+ int reclen2 = 0;
+ unsigned int tocopy;
+ unsigned int block;
+
+ unsigned int mpsWptClass;
+
+ unsigned char copybuf[8192];
+
+ int short_length = atoi(snlen);
+
+ if (mpsmergeout) {
+ /* need to skip over the merging header and test merge version */
+ mps_fileHeader_r(mps_file_temp, &mps_ver_temp);
+
+ if (mpsverout) {
+ if (mps_ver_temp != atoi(mpsverout)) {
+ /* Need to clean up after a junk version specified */
+ /* close the real output file + renamed original output file */
+ /* then delete the "real" file and rename the temporarily renamed file back */
+ gbfclose(mps_file_temp);
+ gbfclose(mps_file_out);
+ QFile::remove(fin_name);
+ QFile::rename(tempname, fin_name);
+ fatal(MYNAME ": merge source version is %d, requested out version is %d\n", mps_ver_temp, atoi(mpsverout));
+ }
+ } else {
+ mpsverout = (char*) xmalloc(10);
+ sprintf(mpsverout,"%d", mps_ver_temp);
+ }
+ }
+
+ if (mpsverout) {
+ mps_ver_out = atoi(mpsverout);
+ } else {
+ mps_ver_out = 5;
+ }
+
+ mkshort_handle = mkshort_new_handle();
+
+ setshort_length(mkshort_handle, short_length);
+
+ if (snwhiteopt) {
+ setshort_whitespace_ok(mkshort_handle, atoi(snwhiteopt));
+ } else {
+ setshort_whitespace_ok(mkshort_handle, 0);
+ }
+
+ mps_fileHeader_w(mps_file_out, mps_ver_out);
+
+ /* .mps file order is wpts, rtes, trks then mapsets. If we've not been asked to write
+ wpts, but we are merging, then read in the waypoints from the original file and
+ write them out, prior to doing rtes.
+ */
+ /* if ((mpsmergeout) && (global_opts.objective != wptdata)) { */
+ if ((mpsmergeout) && (! doing_wpts)) {
+ while (!gbfeof(mps_file_temp)) {
+
+ reclen2 = gbfgetint32(mps_file_temp);
+
+ /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
+ gbfread(&recType, 1, 1, mps_file_temp);
+
+ if (recType == 'W') {
+ gbfwrite(&reclen, 4, 1, mps_file_out); /* write out untouched */
+ gbfwrite(&recType, 1, 1, mps_file_out);
+
+ long tempFilePos = gbftell(mps_file_temp);
+ /* need to read in the waypoint info only because later we may need to check for uniqueness
+ since we're here because the user didn't request waypoints, this should be acceptable */
+ mps_waypoint_r(mps_file_temp, mps_ver_temp, &wpt, &mpsWptClass);
+ mps_wpt_q_add(&written_wpt_head, wpt);
+ delete wpt;
+ /* now return to the start of the waypoint data to do a "clean" copy */
+ gbfseek(mps_file_temp, tempFilePos, SEEK_SET);
+
+ /* copy the data using a "reasonably" sized buffer */
+ for (tocopy = reclen2; tocopy > 0; tocopy -= block) {
+ block = (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy);
+ gbfread(copybuf, block, 1, mps_file_temp);
+ gbfwrite(copybuf, block, 1, mps_file_out);
+ }
+ } else {
+ break;
+ }
+ } /* while (!gbfeof(mps_file_temp)) */
+ } /* if (mpsmergeout) */
+
+ /* irrespective of merging, now write out any waypoints */
+ /* if (global_opts.objective == wptdata) { */
+ if (doing_wpts) {
+
+ if (mpsmergeout) {
+ /* since we're processing waypoints, we should read in from whatever version and write out */
+ /* in the selected version */
+ while (!gbfeof(mps_file_temp)) {
+
+ reclen2 = gbfgetint32(mps_file_temp);
+
+ /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
+ gbfread(&recType, 1, 1, mps_file_temp);
+
+ if (recType == 'W') {
+ /* need to be careful that we aren't duplicating a wpt defined from elsewhere */
+ mps_waypoint_r(mps_file_temp, mps_ver_temp, &wpt, &mpsWptClass);
+ if (mpsWptClass == MPSDEFAULTWPTCLASS) {
+ waypt_add(wpt);
+ } else {
+ delete wpt;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ waypt_disp_all(mps_waypoint_w_unique_wrapper);
+ }
+
+ /* prior to writing any tracks as requested, if we're doing a merge, read in the rtes
+ from the original file and then write them out, ready for tracks to follow
+ */
+
+ /* if ((mpsmergeout) && (global_opts.objective != rtedata)) { */
+ if ((mpsmergeout) && (! doing_rtes)) {
+ while (!gbfeof(mps_file_temp)) {
+
+ /* this might all fail if the relevant waypoints haven't been written */
+ if (recType == 'R') {
+ gbfwrite(&reclen, 4, 1, mps_file_out); /* write out untouched */
+ gbfwrite(&recType, 1, 1, mps_file_out);
+
+ /* copy the data using a "reasonably" sized buffer */
+ for (tocopy = reclen2; tocopy > 0; tocopy -= block) {
+ block = (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy);
+ gbfread(copybuf, block, 1, mps_file_temp);
+ gbfwrite(copybuf, block, 1, mps_file_out);
+ }
+ } else {
+ break;
+ }
+ reclen2 = gbfgetint32(mps_file_temp);
+
+ /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
+ gbfread(&recType, 1, 1, mps_file_temp);
+
+ } /* while (!gbfeof(mps_file_temp)) */
+ } /* if (mpsmergeout) */
+
+ /* routes are next in the wpts, rtes, trks, mapset sequence */
+ /* if (global_opts.objective == rtedata) { */
+ if (doing_rtes) {
+
+ if (mpsmergeout) {
+ /* since we're processing routes, we should read in from whatever version and write out */
+ /* in the selected version */
+ while (!gbfeof(mps_file_temp)) {
+
+ if (recType == 'R') {
+ mps_route_r(mps_file_temp, mps_ver_temp, &rte);
+ } else {
+ break;
+ }
+
+ reclen2 = gbfgetint32(mps_file_temp);
+
+ /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
+ gbfread(&recType, 1, 1, mps_file_temp);
+ }
+ }
+ /* need to make sure there is a "real" waypoint for each route waypoint
+ Need to be careful about creating duplicate wpts as MapSource chokes on these
+ so, if the user requested waypoints to be output too, then write the route
+ waypoints only if unique in the total list of waypoints ("real" and route derived)
+ If the user didn't request waypoints to be output, then output the route derived
+ waypoints without consideration for uniqueness for "real" waypoints that haven't
+ been output (phew!)
+ */
+ route_disp_all(nullptr, nullptr, mps_route_wpt_w_unique_wrapper);
+
+ route_disp_all(mps_routehdr_w_wrapper, mps_routetrlr_w_wrapper, mps_routedatapoint_w_wrapper);
+ }
+
+ /* If merging but we haven't been requested to write out tracks, then read in tracks from
+ the original file and write these out prior to any mapset writes later on
+ */
+ /* if ((mpsmergeout) && (global_opts.objective != trkdata)) { */
+ if ((mpsmergeout) && (! doing_trks)) {
+ while (!gbfeof(mps_file_temp)) {
+
+ if (recType == 'T') {
+ gbfwrite(&reclen, 4, 1, mps_file_out); /* write out untouched */
+ gbfwrite(&recType, 1, 1, mps_file_out);
+
+ /* copy the data using a "reasonably" sized buffer */
+ for (tocopy = reclen2; tocopy > 0; tocopy -= block) {
+ block = (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy);
+ gbfread(copybuf, block, 1, mps_file_temp);
+ gbfwrite(copybuf, block, 1, mps_file_out);
+ }
+ } else {
+ break;
+ }
+ reclen2 = gbfgetint32(mps_file_temp);
+
+ /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
+ gbfread(&recType, 1, 1, mps_file_temp);
+
+ } /* while (!gbfeof(mps_file_temp)) */
+ } /* if (mpsmergeout) */
+
+ /* tracks are next in the wpts, rte, trks, mapset sequence in .mps files */
+ /* if (global_opts.objective == trkdata) { */
+ if (doing_trks) {
+ if (mpsmergeout) {
+ /* since we're processing tracks, we should read in from whatever version and write out
+ in the selected version */
+ while (!gbfeof(mps_file_temp)) {
+
+ if (recType == 'T') {
+ mps_track_r(mps_file_temp, mps_ver_temp, &trk);
+ } else {
+ break;
+ }
+
+ reclen2 = gbfgetint32(mps_file_temp);
+
+ /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
+ gbfread(&recType, 1, 1, mps_file_temp);
+ }
+ }
+ track_disp_all(mps_trackhdr_w_wrapper, nullptr, mps_trackdatapoint_w_wrapper);
+ }
+
+ if (mpsmergeout) {
+ /* should now be reading a either a map segment or a mapset - since we would write out an empty one,
+ let's use the one from the merge file which may well have decent data in */
+ for (;;) {
+ gbfwrite(&reclen, 4, 1, mps_file_out); /* write out untouched */
+ gbfwrite(&recType, 1, 1, mps_file_out);
+
+ /* copy the data using a "reasonably" sized buffer */
+ for (tocopy = reclen2; tocopy > 0; tocopy -= block) {
+ block = (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy);
+ gbfread(copybuf, block, 1, mps_file_temp);
+ gbfwrite(copybuf, block, 1, mps_file_out);
+ }
+
+ if (recType != 'V') {
+ reclen2 = gbfgetint32(mps_file_temp);
+
+ /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
+ gbfread(&recType, 1, 1, mps_file_temp);
+ } else {
+ break;
+ }
+ }
+
+ } else {
+ mps_mapsetname_w(mps_file_out, mps_ver_out);
+ }
+
+ mkshort_del_handle(&mkshort_handle);
+
+}
+
+ff_vecs_t mps_vecs = {
+ ff_type_file,
+ FF_CAP_RW_ALL,
+ mps_rd_init,
+ mps_wr_init,
+ mps_rd_deinit,
+ mps_wr_deinit,
+ mps_read,
+ mps_write,
+ nullptr,
+ &mps_args,
+ CET_CHARSET_MS_ANSI, 0, /* CET-REVIEW */
+ NULL_POS_OPS,
+ nullptr,
+};
+++ /dev/null
-/*
- Access to Garmin MapSource files.
- Based on information provided by Ian Cowley & Mark Bradley
-
- Copyright (C) 2002 Robert Lipe, robertlipe+source@gpsbabel.org
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-/* #define MPS_DEBUG 0 */
-
-#include <cstdio> // for SEEK_CUR, sprintf, SEEK_SET, EOF, size_t
-#include <cstdlib> // for atoi, rand, srand
-#include <cstring> // for strcpy, memset, strlen, strcmp
-#include <ctime> // for time_t
-#include <cstdio> // for SEEK_CUR
-
-#include <QtCore/QChar> // for QChar
-#include <QtCore/QFile> // for QFile
-#include <QtCore/QList> // for QList
-#include <QtCore/QString> // for QString, operator==
-#include <QtCore/QtGlobal> // for foreach
-
-#include "defs.h"
-#include "garmin_tables.h" // for gt_find_icon_number_from_desc, MAPSOURCE, gt_find_desc_from_icon_number, GARMIN_SERIAL, PCX, garmin_formats_e
-#include "gbfile.h" // for gbfwrite, gbfread, gbfgetint32, gbfputint32, gbfseek, gbfputc, gbfgetc, gbfputdbl, gbfgetdbl, gbfclose, gbfeof, gbfile, gbftell, gbfgetcstr, gbfputs, gbfopen_le
-#include "jeeps/gpsmath.h" // for GPS_Math_Deg_To_Semi, GPS_Math_Semi_To_Deg
-#include "src/core/datetime.h" // for DateTime
-
-
-static gbfile* mps_file_in;
-static gbfile* mps_file_out;
-static gbfile* mps_file_temp;
-static short_handle mkshort_handle;
-
-static int mps_ver_in = 0;
-static int mps_ver_out = 0;
-static int mps_ver_temp = 0;
-
-/* Temporary pathname used when merging gpsbabel output with an existing file */
-static QString tempname;
-static QString fin_name;
-
-static const Waypoint* prevRouteWpt;
-/* Private queues of written out waypoints */
-static QList<Waypoint *> written_wpt_head;
-static QList<Waypoint *> written_route_wpt_head;
-static short_handle written_wpt_mkshort_handle;
-
-/* Private queue of read in waypoints assumed to be used only for routes */
-static QList<Waypoint *> read_route_wpt_head;
-static short_handle read_route_wpt_mkshort_handle;
-
-#define MPSDEFAULTWPTCLASS 0
-#define MPSHIDDENROUTEWPTCLASS 8
-
-#define MYNAME "MAPSOURCE"
-#define ISME 0
-#define NOTME 1
-
-#define DEFAULTICONDESCR "Waypoint"
-#define DEFAULTICONVALUE 18
-
-#define MPSNAMEBUFFERLEN 1024
-#define MPSNOTESBUFFERLEN 4096
-#define MPSDESCBUFFERLEN 4096
-
-
-static char* snlen = nullptr;
-static char* snwhiteopt = nullptr;
-static char* mpsverout = nullptr;
-static char* mpsmergeouts = nullptr;
-static int mpsmergeout;
-static char* mpsusedepth = nullptr;
-static char* mpsuseprox = nullptr;
-
-static
-QVector<arglist_t> mps_args = {
- {
- "snlen", &snlen, "Length of generated shortnames", "10", ARGTYPE_INT, "1",
- nullptr, nullptr
- },
- {
- "snwhite", &snwhiteopt, "Allow whitespace synth. shortnames",
- nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
- {
- "mpsverout", &mpsverout,
- "Version of mapsource file to generate (3,4,5)", nullptr,
- ARGTYPE_INT, ARG_NOMINMAX, nullptr
- },
- {
- "mpsmergeout", &mpsmergeouts, "Merge output with existing file",
- nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
- {
- "mpsusedepth", &mpsusedepth,
- "Use depth values on output (default is ignore)", nullptr,
- ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
- {
- "mpsuseprox", &mpsuseprox,
- "Use proximity values on output (default is ignore)",
- nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
- },
-};
-
-static void
-mps_wpt_q_init(QList<Waypoint *>* whichQueue)
-{
- whichQueue->clear();
-}
-
-static void
-mps_wpt_q_deinit(QList<Waypoint *>* whichQueue)
-{
- while (!whichQueue->isEmpty()) {
- delete whichQueue->takeFirst();
- }
-}
-
-/*
- * Find a waypoint that we've already written out
- *
- */
-static Waypoint*
-mps_find_wpt_q_by_name(const QList<Waypoint *>* whichQueue, const QString& name)
-{
- foreach (Waypoint* waypointp, *whichQueue) {
- if (waypointp->shortname == name) {
- return waypointp;
- }
- }
- return nullptr;
-}
-
-/*
- * Add a waypoint that we've already written out to our list
- *
- */
-static void
-mps_wpt_q_add(QList<Waypoint *>* whichQueue, const Waypoint* wpt)
-{
- auto* written_wpt = new Waypoint(*wpt);
- whichQueue->append(written_wpt);
-}
-
-static int
-mps_converted_icon_number(const int icon_num, const int mpsver, garmin_formats_e garmin_format)
-{
- int def_icon = DEFAULTICONVALUE;
-
- switch (garmin_format) {
- case MAPSOURCE:
- if (mpsver == 5) {
- return icon_num;
- }
- if (mpsver == 4) {
- /* Water hydrant */
- if (icon_num == 139) {
- return def_icon;
- } else {
- return icon_num;
- }
- } else {
- /* the Contact icons - V3 doesn't have anything like this */
- if ((icon_num >= 119) && (icon_num <= 138)) {
- return def_icon;
- }
- /* the Geocache icons - V3 use the Circle with X */
- if ((icon_num >= 117) && (icon_num <= 118)) {
- return 65;
- }
- /* Water hydrant */
- if (icon_num == 139) {
- return def_icon;
- }
- return icon_num;
- }
-
- case PCX:
- case GARMIN_SERIAL:
- if (mpsver == 5) {
- return icon_num;
- }
- if (mpsver == 4) {
- /* Water hydrant */
- if (icon_num == 8282) {
- return def_icon;
- } else {
- return icon_num;
- }
- }
- /* the Contact icons - V3 doesn't have anything like this */
- if ((icon_num >= 8257) && (icon_num <= 8276)) {
- return def_icon;
- }
- /* the Geocache icons - V3 use the Circle with X */
- if ((icon_num >= 8255) && (icon_num <= 8256)) {
- return 179;
- }
- /* Water hydrant */
- if (icon_num == 8282) {
- return def_icon;
- }
- return icon_num;
-
- default:
- fatal(MYNAME ": unknown garmin format.\n");
- }
- return def_icon;
-}
-
-static void
-mps_rd_init(const QString& fname)
-{
- mps_file_in = gbfopen_le(fname, "rb", MYNAME);
-
- read_route_wpt_mkshort_handle = mkshort_new_handle();
- /* initialise the "private" queue of waypoints read for routes */
- mps_wpt_q_init(&read_route_wpt_head);
-}
-
-static void
-mps_rd_deinit()
-{
- gbfclose(mps_file_in);
- if (read_route_wpt_mkshort_handle) {
- mkshort_del_handle(&read_route_wpt_mkshort_handle);
- }
- /* flush the "private" queue of waypoints read for routes */
- mps_wpt_q_deinit(&read_route_wpt_head);
-}
-
-static void
-mps_wr_init(const QString& fname)
-{
- fin_name = fname;
- if (mpsmergeouts) {
- mpsmergeout = atoi(mpsmergeouts);
- }
-
- if (mpsmergeout) {
- mps_file_out = gbfopen_le(fname, "rb", MYNAME);
- if (mps_file_out == nullptr) {
- mpsmergeout = 0;
- } else {
- gbfclose(mps_file_out);
- srand((unsigned) current_time().toTime_t());
-
- for (;;) {
- /* create a temporary name based on a random char and the existing name */
- /* then test if it already exists, if so try again with another rand num */
- /* yeah, yeah, so there's probably a library function for this */
- tempname = QString("%1.%2").arg(fname).arg(rand(), 8, 16, QChar('0'));
- mps_file_temp = gbfopen_le(tempname, "rb", MYNAME);
- if (mps_file_temp == nullptr) {
- break;
- }
- gbfclose(mps_file_temp);
- }
- QFile::rename(fname, tempname);
- mps_file_temp = gbfopen_le(tempname, "rb", MYNAME);
- }
- }
-
- mps_file_out = gbfopen_le(fname, "wb", MYNAME);
-
- written_wpt_mkshort_handle = mkshort_new_handle();
- /* initialise the "private" queue of waypoints written */
- mps_wpt_q_init(&written_wpt_head);
- mps_wpt_q_init(&written_route_wpt_head);
-}
-
-static void
-mps_wr_deinit()
-{
- gbfclose(mps_file_out);
-
- if (mpsmergeout) {
- gbfclose(mps_file_temp);
- QFile::remove(tempname);
- tempname.clear();
- }
-
- if (written_wpt_mkshort_handle) {
- mkshort_del_handle(&written_wpt_mkshort_handle);
- }
- /* flush the "private" queue of waypoints written */
- mps_wpt_q_deinit(&written_wpt_head);
- mps_wpt_q_deinit(&written_route_wpt_head);
- fin_name.clear();
-}
-
-/*
- * get characters until and including terminating NULL from mps_file_in
- * and write into buf.
- */
-static void
-mps_readstr(gbfile* mps_file, char* buf, size_t sz)
-{
- int c;
- buf[sz-1] = 0;
- while (--sz && (c = gbfgetc(mps_file)) != EOF) {
- *buf++ = c;
- if (c == 0) {
- return;
- }
- }
-}
-
-/*
- * read in from file to check a) valid format b) version of data formatting
- * MRCB
- */
-static void
-mps_fileHeader_r(gbfile* mps_file, int* mps_ver)
-{
- char hdr[100];
-
- mps_readstr(mps_file, hdr, sizeof(hdr));
- if (strcmp(hdr, "MsRcd")) {
- fatal(MYNAME ": This doesn't look like a mapsource file.\n");
- }
- /* Read record length of "format details" section */
- int reclen = gbfgetint32(mps_file);
- /* Read the "format details" in plus the trailing null */
- gbfread(hdr, 3, 1, mps_file);
- if (hdr[0] != 'D') {
- /* No flag for the "data" section */
- fatal(MYNAME ": This doesn't look like a mapsource file.\n");
- }
- if (hdr[1] == 'd') {
- *mps_ver = 3;
- } else if ((hdr[1] > 'd') && (hdr[1] <= 'h')) {
- *mps_ver = 4;
- } else if ((hdr[1] > 'h') && (hdr[1] <= 'i')) {
- *mps_ver = 5;
- } else {
- fatal(MYNAME ": Unsupported version of mapsource file.\n");
- }
- /* Skip reliably over the "format details" section */
- gbfseek(mps_file, reclen+1-3, SEEK_CUR);
- /* Read record length of "program signature" section */
- reclen = gbfgetint32(mps_file);
- /* Skip reliably over the "program signature" section */
- if (reclen >= 0) {
- gbfseek(mps_file, reclen+1, SEEK_CUR);
- }
-}
-
-/*
- * write out to file
- * MRCB
- */
-static void
-mps_fileHeader_w(gbfile* mps_file, int mps_ver)
-{
- char hdr[100];
-
- strcpy(hdr, "MsRc");
- gbfwrite(hdr, 4, 1, mps_file);
-
- /* Between versions 3 & 5 this value is 'd', but might change in the future */
- strcpy(hdr, "d");
- gbfwrite(hdr, 2, 1, mps_file); /* include trailing NULL char */
-
- /* Start of a "Data" section */
- hdr[0] = 'D';
- /* if (mps_ver == 3) */
- hdr[1] = 'd'; /* equates to V3.02 */
- if (mps_ver == 4) {
- hdr[1] = 'g'; /* equates to V4.06 */
- }
- if (mps_ver == 5) {
- hdr[1] = 'i'; /* equates to V5.0 */
- }
- hdr[2] = 0;
-
- int reclen = 2; /* this is 3 byte record */
- gbfputint32(reclen, mps_file);
- gbfwrite(hdr, 3, 1, mps_file); /* reclen + 1 */
-
- hdr[0] = 'A';
- /* if (mps_ver == 3) */
- hdr[1] = 0x2E;
- hdr[2] = 0x01; /* equates to V3.02 */
- hdr[3] = 'S';
- hdr[4] = 'Q';
- hdr[5] = 'A';
- hdr[6] = 0;
- strcpy(hdr+7,"Oct 20 1999");
- strcpy(hdr+19,"12:50:33");
- if (mps_ver == 4) {
- hdr[1] = (char) 0x96; /* equates to V4.06 */
- strcpy(hdr+7,"Oct 22 2001");
- strcpy(hdr+19,"15:45:33");
- }
- if (mps_ver == 5) {
- hdr[1] = (char) 0xF4; /* equates to V5.0 */
- strcpy(hdr+7,"Jul 3 2003");
- strcpy(hdr+19,"08:35:33");
- }
-
- reclen = 27; /* pre measured! */
- gbfputint32(reclen, mps_file);
- gbfwrite(hdr, 28, 1, mps_file); /* reclen + 1 - can't use this as reclen may be wrongendian now */
-}
-
-/*
- * read in from file a map segment record
- * MRCB
- */
-static void
-mps_mapsegment_r(gbfile* mps_file, int mps_ver)
-{
- int reclen;
-
- (void)mps_ver;
-
-#if 0
- /* At the moment we're not doing anything with map segments, but here's the template code as if we were */
- char hdr[100];
- gbfread(&CDid, 4, 1, mps_file);
- reclen = le_read32(&CDid);
-
- gbfread(&CDSegmentid, 4, 1, mps_file);
- reclen = le_read32(&CDSegmentid);
-
- mps_readstr(mps_file, CDName, sizeof(CDName));
- mps_readstr(mps_file, CDSegmentName, sizeof(CDSegmentName));
- mps_readstr(mps_file, CDAreaName, sizeof(CDAreaName));
-
- gbfread(hdr, 4, 1, mps_file); /* trailing long value */
-#endif
-
- gbfseek(mps_file, -5, SEEK_CUR);
- reclen = gbfgetint32(mps_file);
- if (reclen >= 0) {
- gbfseek(mps_file, reclen+1, SEEK_CUR);
- }
-}
-
-
-/*
- * read in from file a mapsetname record
- * there should always be one of these at the end of the file
- * MRCB
- */
-static void
-mps_mapsetname_r(gbfile* mps_file, int mps_ver)
-{
- (void)mps_ver;
-
- /* At the moment we're not doing anything with mapsetnames, but here's the template code as if we were
- char hdr[100];
- mps_readstr(mps_file, hdr, sizeof(hdr));
- char mapsetnamename[very large number?];
- strcpy(mapsetnamename,hdr);
- char mapsetnameAutonameFlag;
- gbfread(&mapsetnameAutonameFlag, 1, 1, mps_file); */
-
- gbfseek(mps_file, -5, SEEK_CUR);
- int reclen = gbfgetint32(mps_file);
- gbfseek(mps_file, reclen+1, SEEK_CUR);
-}
-
-
-/*
- * write out to file a mapsetname record
- * there should always be one of these at the end of the file
- * MRCB
- */
-static void
-mps_mapsetname_w(gbfile* mps_file, int mps_ver)
-{
- char hdr[100];
-
- (void)mps_ver;
-
- hdr[0] = 'V'; /* mapsetname start of record indicator */
- hdr[1] = 0; /* zero length null terminated string */
- hdr[2] = 1; /* mapsetname autoname flag set to DO autoname */
- int reclen = 2; /* three bytes of the V record */
- gbfputint32(reclen, mps_file);
- gbfwrite(hdr, 3, 1, mps_file); /* reclen + 1 */
-}
-
-
-/*
- * read in from file a waypoint record
- * MRCB
- */
-static void
-mps_waypoint_r(gbfile* mps_file, int mps_ver, Waypoint** wpt, unsigned int* mpsclass)
-{
- char tbuf[100];
- char wptname[MPSNAMEBUFFERLEN];
- double mps_altitude = unknown_alt;
- double mps_proximity = unknown_alt;
- double mps_depth = unknown_alt;
-
- auto* thisWaypoint = new Waypoint;
- *wpt = thisWaypoint;
-
- mps_readstr(mps_file, wptname, sizeof(wptname));
-
- (*mpsclass) = gbfgetint32(mps_file); /* class */
- mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* country */
-
- gbfread(tbuf,17, 1, mps_file); /* subclass data (17) */
-
- if ((mps_ver == 4) || (mps_ver == 5)) {
- gbfread(tbuf, 5, 1, mps_file); /* additional subclass data (1) & terminator? (4) */
- }
-
- int lat = gbfgetint32(mps_file);
- int lon = gbfgetint32(mps_file);
-
- if (gbfgetc(mps_file) == 1) { /* altitude validity */
- mps_altitude = gbfgetdbl(mps_file);
- } else {
- mps_altitude = unknown_alt;
- gbfseek(mps_file, 8, SEEK_CUR);
- }
-
- QString wptdesc = gbfgetcstr(mps_file);
-
- if (gbfgetc(mps_file) == 1) { /* proximity validity */
- mps_proximity = gbfgetdbl(mps_file);
- } else {
- mps_proximity = unknown_alt;
- gbfseek(mps_file, 8, SEEK_CUR);
- }
-
- (void) gbfgetint32(mps_file); /* display flag */
- (void) gbfgetint32(mps_file); /* colour */
- int icon = gbfgetint32(mps_file); /* display symbol */
-
- mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* city */
- mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* state */
- mps_readstr(mps_file, tbuf, sizeof(tbuf)); /*facility */
-
- gbfread(tbuf, 1, 1, mps_file); /* unknown */
-
- if (gbfgetc(mps_file) == 1) { /* depth validity */
- mps_depth = gbfgetdbl(mps_file);
- } else {
- mps_depth = unknown_alt;
- (void) gbfseek(mps_file, 8, SEEK_CUR);
- }
-
- if ((mps_ver == 4) || (mps_ver == 5)) {
- gbfread(tbuf, 6, 1, mps_file); /* unknown */
- thisWaypoint->notes = gbfgetcstr(mps_file);
- } else {
- gbfread(tbuf, 2, 1, mps_file); /* unknown */
- }
-
- thisWaypoint->shortname = wptname;
- thisWaypoint->description = wptdesc;
- thisWaypoint->latitude = GPS_Math_Semi_To_Deg(lat);
- thisWaypoint->longitude = GPS_Math_Semi_To_Deg(lon);
- thisWaypoint->altitude = mps_altitude;
- if (mps_proximity != unknown_alt) {
- WAYPT_SET(thisWaypoint, proximity, mps_proximity);
- }
- if (mps_depth != unknown_alt) {
- WAYPT_SET(thisWaypoint, depth, mps_depth);
- }
-
- /* might need to change this to handle version dependent icon handling */
- thisWaypoint->icon_descr = gt_find_desc_from_icon_number(icon, MAPSOURCE);
-}
-
-/*
- * write out to file a waypoint record
- * MRCB
- */
-static void
-mps_waypoint_w(gbfile* mps_file, int mps_ver, const Waypoint* wpt, const bool isRouteWpt)
-{
- char zbuf[25];
- char ffbuf[25];
- int display = 1;
- int colour = 0; /* (unknown colour) black is 1, white is 16 */
-
- double mps_altitude = wpt->altitude;
- double mps_proximity = (mpsuseprox ? WAYPT_GET(wpt, proximity, unknown_alt) : unknown_alt);
- double mps_depth = unknown_alt;
-
- int lat = GPS_Math_Deg_To_Semi(wpt->latitude);
- int lon = GPS_Math_Deg_To_Semi(wpt->longitude);
- if (WAYPT_HAS(wpt, depth) && mpsusedepth) {
- mps_depth = wpt->depth;
- }
- QString src;
- if (!wpt->description.isEmpty()) {
- src = wpt->description;
- }
- if (!wpt->notes.isEmpty()) {
- src = wpt->notes;
- }
- QString ident = global_opts.synthesize_shortnames ?
- mkshort(mkshort_handle, src) :
- CSTRc(wpt->shortname);
-
- memset(zbuf, 0, sizeof(zbuf));
- memset(ffbuf, 0xff, sizeof(ffbuf));
-
- /* might need to change this to handle version dependent icon handling */
- int icon = gt_find_icon_number_from_desc(wpt->icon_descr, MAPSOURCE);
- if (get_cache_icon(wpt)) {
- icon = gt_find_icon_number_from_desc(get_cache_icon(wpt), MAPSOURCE);
- }
-
- icon = mps_converted_icon_number(icon, mps_ver, MAPSOURCE);
-
- /* two NULL (0x0) bytes at end of each string */
- char* ascii_description = xstrdup(wpt->description);
- int reclen = ident.length() + strlen(ascii_description) + 2;
- if ((mps_ver == 4) || (mps_ver == 5)) {
- /* v4.06 & V5.0*/
- reclen += 85; /* "W" (1) + strlen(name) + NULL (1) + class(4) + country(sz) +
- subclass(18) + unknown(4) + lat(4) + lon(4) + alt(9) + strlen(desc)
- + NULL (1) + prox(9) + display(4) + colour(4) + symbol(4) + city(sz) +
- state(sz) + facility(sz) + unknown2(1) + depth(9) + unknown3(7) */
- /* -1 as reclen is interpreted from zero meaning a reclength of one */
- if (!wpt->notes.isEmpty()) {
- reclen += strlen(CSTRc(wpt->notes));
- }
- } else {
- /* v3.02 */
- reclen += 75; /* "W" (1) + strlen(name) + NULL (1) + + class(4) + country(sz) +
- subclass(17) + lat(4) + lon(4) + alt(9) + strlen(desc) +
- NULL (1) + prox(9) + display(4) +
- colour(4) + symbol(4) + city(sz) + state(sz) + facility(sz) +
- unknown2(1) + depth(9) + unknown3(2) */
- /* -1 as reclen is interpreted from zero meaning a reclength of one */
- }
-
- gbfputint32(reclen, mps_file);
- gbfwrite("W", 1, 1, mps_file);
- gbfputs(ident, mps_file);
- gbfwrite(zbuf, 1, 1, mps_file); /* NULL termination to ident */
-
- if (isRouteWpt) {
- zbuf[0] = (char)MPSHIDDENROUTEWPTCLASS;
- } else {
- zbuf[0] = (char)MPSDEFAULTWPTCLASS;
- }
- gbfwrite(zbuf, 4, 1, mps_file); /* class */
-
- zbuf[0]=0;
- gbfwrite(zbuf, 1, 1, mps_file); /* country empty string */
-
- if ((mps_ver == 4) || (mps_ver == 5)) {
- gbfwrite(zbuf, 4, 1, mps_file); /* subclass part 1 */
- gbfwrite(ffbuf, 12, 1, mps_file); /* subclass part 2 */
- gbfwrite(zbuf, 2, 1, mps_file); /* subclass part 3 */
- gbfwrite(ffbuf, 4, 1, mps_file); /* unknown */
- } else {
- gbfwrite(zbuf, 8, 1, mps_file);
- gbfwrite(ffbuf, 8, 1, mps_file);
- gbfwrite(zbuf, 1, 1, mps_file);
- }
-
- gbfputint32(lat, mps_file);
- gbfputint32(lon, mps_file);
-
- if (mps_altitude == unknown_alt) {
- gbfwrite(zbuf, 9, 1, mps_file);
- } else {
- gbfputc(1, mps_file);
- gbfputdbl(mps_altitude, mps_file);
- }
- if (!wpt->description.isEmpty()) {
- gbfputs(ascii_description, mps_file);
- }
- gbfwrite(zbuf, 1, 1, mps_file); /* NULL termination */
- xfree(ascii_description);
- ascii_description = nullptr;
-
- if (mps_proximity == unknown_alt) {
- gbfwrite(zbuf, 9, 1, mps_file);
- } else {
- gbfputc(1, mps_file);
- gbfputdbl(mps_proximity, mps_file);
- }
-
- gbfputint32(display, mps_file); /* Show waypoint w/ name */
- gbfputint32(colour, mps_file);
- gbfputint32(icon, mps_file);
-
- gbfwrite(zbuf, 3, 1, mps_file); /* city, state, facility */
-
- gbfwrite(zbuf, 1, 1, mps_file); /* unknown */
-
- if (mps_depth == unknown_alt) {
- gbfwrite(zbuf, 9, 1, mps_file);
- } else {
- gbfputc(1, mps_file);
- gbfputdbl(mps_depth, mps_file);
- }
-
- gbfwrite(zbuf, 2, 1, mps_file); /* unknown */
- if ((mps_ver == 4) || (mps_ver == 5)) {
- gbfwrite(zbuf, 4, 1, mps_file); /* unknown */
- if (!wpt->notes.isEmpty()) {
- gbfputs(wpt->notes, mps_file);
- }
- gbfwrite(zbuf, 1, 1, mps_file); /* string termination */
- }
-}
-
-/*
- * wrapper to include the mps_ver_out information
- * A waypoint is only written if it hasn't been written before
- * based on it shortname alone
- *
- */
-static void
-mps_waypoint_w_unique_wrapper(const Waypoint* wpt)
-{
- /* Search for this waypoint in the ones already written */
- Waypoint* wptfound = mps_find_wpt_q_by_name(&written_wpt_head, CSTRc(wpt->shortname));
- /* is the next line necessary? Assumes we know who's called us and in what order */
- if (wptfound == nullptr) {
- wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, CSTRc(wpt->shortname));
- }
-
- /* if this waypoint hasn't been written then it is okay to do so */
- if (wptfound == nullptr) {
- mps_waypoint_w(mps_file_out, mps_ver_out, wpt, false);
-
- /* ensure we record in our "private" queue what has been
- written so that we don't write it again */
- mps_wpt_q_add(&written_wpt_head, wpt);
- }
-}
-
-/*
- * wrapper to include the mps_ver_out information
- * A waypoint is only written if it hasn't been written before
- * based on it shortname alone
- * Provided as a separate function from above in case we find
- * have to do other things
- *
- */
-static void
-mps_route_wpt_w_unique_wrapper(const Waypoint* wpt)
-{
- /* Search for this waypoint in the ones already written */
- Waypoint* wptfound = mps_find_wpt_q_by_name(&written_wpt_head, CSTRc(wpt->shortname));
- if (wptfound == nullptr)
- /* so, not a real wpt, so must check route wpts already written as reals */
- {
- wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, CSTRc(wpt->shortname));
- }
-
- /* if this waypoint hasn't been written then it is okay to do so
- but assume it is only required for the route
- */
- if (wptfound == nullptr) {
- /* Although we haven't written one out, this might still be a "real" waypoint
- If so, we need to write it out now accordingly */
- wptfound = find_waypt_by_name(wpt->shortname);
-
- if (wptfound == nullptr) {
- /* well, we tried to find: it wasn't written and isn't a real waypoint */
- mps_waypoint_w(mps_file_out, mps_ver_out, wpt, true);
- mps_wpt_q_add(&written_route_wpt_head, wpt);
- } else {
- mps_waypoint_w(mps_file_out, mps_ver_out, wpt, false);
- /* Simulated real user waypoint */
- mps_wpt_q_add(&written_wpt_head, wpt);
- }
- }
-}
-#if 0
-/*
- * wrapper to include the mps_ver_out information
- * This one always writes a waypoint. If it has been written before
- * then generate a unique name before writing
- *
- */
-static void
-mps_waypoint_w_uniqloc_wrapper(Waypoint* wpt)
-{
- Waypoint* wptfound = NULL;
- char* newName;
-
- /* Search for this waypoint in the ones already written */
- wptfound = mps_find_wpt_q_by_name(&written_wpt_head, wpt->shortname);
- /* is the next line necessary? Assumes we know who's called us and in what order */
- if (wptfound == NULL) {
- wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, wpt->shortname);
- }
-
- if (wptfound != NULL) {
- /* check if this is the same waypoint by looking at the lat lon
- not ideal, but better then having two same named waypoints
- that kills MapSource. If it is the same then don't bother
- adding it in. If it isn't, then rename it
- */
- if (((wpt->latitude - wptfound->latitude) != 0) ||
- ((wpt->longitude - wptfound->longitude) != 0)) {
- /* Not the same lat lon, so rename and add */
- newName = mkshort(written_wpt_mkshort_handle, wpt->shortname);
- wptfound = new Waypoint(*wpt);
- xfree(wptfound->shortname);
- wptfound->shortname = newName;
- mps_waypoint_w(mps_file_out, mps_ver_out, wptfound, false);
- mps_wpt_q_add(&written_wpt_head, wpt);
- }
- } else {
- mps_waypoint_w(mps_file_out, mps_ver_out, wpt, false);
- /* ensure we record in out "private" queue what has been
- written so that we don't write it again */
- mps_wpt_q_add(&written_wpt_head, wpt);
- }
-}
-#endif
-
-/*
- * read in from file a route record
- * MRCB
- */
-static void
-mps_route_r(gbfile* mps_file, int mps_ver, route_head** rte)
-{
- char tbuf[100];
- char wptname[MPSNAMEBUFFERLEN];
- int lat = 0;
- int lon = 0;
- char rte_autoname;
- int interlinkStepCount;
- unsigned int mpsclass;
-
- route_head* rte_head;
- int rte_count;
-
- Waypoint* thisWaypoint;
- Waypoint* tempWpt;
-
- double mps_altitude = unknown_alt;
- double mps_depth = unknown_alt;
-
- QString rtename = gbfgetcstr(mps_file);
-#ifdef MPS_DEBUG
- fprintf(stderr, "mps_route_r: reading route %s\n", rtename);
-#endif
-
- gbfread(&rte_autoname, 1, 1, mps_file); /* autoname flag */
-
- gbfread(tbuf, 1, 1, mps_file); /* skip min/max values */
- if (tbuf[0] == 0) {
-
- lat = gbfgetint32(mps_file); /* max lat of whole route */
- lon = gbfgetint32(mps_file); /* max lon of whole route */
-
- if (gbfgetc(mps_file) == 1) { /* altitude validity */
- mps_altitude = gbfgetdbl(mps_file);
- } else {
- mps_altitude = unknown_alt;
- gbfseek(mps_file, 8, SEEK_CUR);
- }
-
- lat = gbfgetint32(mps_file); /* min lat of whole route */
- lon = gbfgetint32(mps_file); /* min lon of whole route */
-
- if (gbfgetc(mps_file) == 1) { /* altitude validity */
- mps_altitude = gbfgetdbl(mps_file);
- } else {
- mps_altitude = unknown_alt;
- gbfseek(mps_file, 8, SEEK_CUR);
- }
- }
-
- rte_count = gbfgetint32(mps_file); /* number of waypoints in route */
-
- /* This might be rather presumptuous, but is it valid in any format to have route with no points? */
- /* Let's assume not, so if the route count is zero or less, let's get out of here and allow the */
- /* caller to do any file resync */
- if (rte_count < 0) {
- return;
- }
-
-#ifdef MPS_DEBUG
- fprintf(stderr, "mps_route_r: route contains %d waypoints\n", rte_count);
-#endif
-
- rte_head = new route_head;
- rte_head->rte_name = rtename;
- route_add_head(rte_head);
- *rte = rte_head;
-
- rte_count--; /* need to loop round for one less than the number of waypoints */
-
- while (rte_count--) {
-
- mps_readstr(mps_file, wptname, sizeof(wptname));
-#ifdef MPS_DEBUG
- fprintf(stderr, "mps_route_r: reading route waypoint %s\n", wptname);
-#endif
-
- mpsclass = gbfgetint32(mps_file); /* class */
- (void)mpsclass;
- mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* country */
-
- if ((mps_ver == 4) || (mps_ver == 5)) {
- gbfread(tbuf, 22, 1, mps_file); /* subclass data */
-
- /* This is a bit unpleasant. Routes have a variable length of
- data (min 22 bytes) terminated by a zero */
- do {
- gbfread(tbuf, 1, 1, mps_file);
- } while (tbuf[0] && !gbfeof(mps_file));
-
- /* The next thing is the unknown 0x03 0x00 .. 0x00 (18 bytes) */
- gbfread(tbuf, 18, 1, mps_file);
- } else {
- gbfread(tbuf, 17, 1, mps_file); /* subclass data */
- gbfread(tbuf, 18, 1, mps_file); /* unknown 0x00 0x03 0x00 .. 0x00 */
- }
-
- /* link details */
- interlinkStepCount = gbfgetint32(mps_file); /* NOT always 2, but will assume > 0 */
-
-#ifdef MPS_DEBUG
- fprintf(stderr, "mps_route_r: interlink steps are %d\n", interlinkStepCount);
-#endif
-
- /* Basically we're knackered if the step count is less than one since we hard code reading of the */
- /* first, so if there isn't one, we'd lose sync on the file and read junk */
- /* Given we've already done some route head allocation, do we return or do we die? It'd be good */
- /* do some clean up before returning. */
- if (interlinkStepCount < 1) {
- /* For RJL - are the following lines correct ? */
- /* route_free(rte_head);
- route_del_head(rte_head); */
- return;
- }
-
- /* first end of link */
- lat = gbfgetint32(mps_file);
- lon = gbfgetint32(mps_file);
-
- if (gbfgetc(mps_file) == 1) { /* altitude validity */
- mps_altitude = gbfgetdbl(mps_file);
- } else {
- mps_altitude = unknown_alt;
- gbfseek(mps_file, 8, SEEK_CUR);
- }
-
- /* with MapSource routes, the real waypoint details are held as a separate waypoint, so copy from there
- if found. With MapSource, one should consider the real waypoint list as definitive */
- tempWpt = find_waypt_by_name(wptname);
-
- if (tempWpt != nullptr) {
- thisWaypoint = new Waypoint(*tempWpt);
- } else {
- tempWpt = mps_find_wpt_q_by_name(&read_route_wpt_head, wptname);
-
- if (tempWpt != nullptr) {
- thisWaypoint = new Waypoint(*tempWpt);
- } else {
- /* should never reach here, but we do need a fallback position */
-#ifdef MPS_DEBUG
- fprintf(stderr, "mps_route_r: reached the point we never should\n");
-#endif
- thisWaypoint = new Waypoint;
- thisWaypoint->shortname = wptname;
- thisWaypoint->latitude = GPS_Math_Semi_To_Deg(lat);
- thisWaypoint->longitude = GPS_Math_Semi_To_Deg(lon);
- thisWaypoint->altitude = mps_altitude;
- if (mps_depth != unknown_alt) {
- WAYPT_SET(thisWaypoint, depth, mps_depth);
- }
- }
- }
-
- route_add_wpt(rte_head, thisWaypoint);
-
- /* take two off the count since we separately read the start and end parts of the link */
- /* MRCB 2004/09/15 - NOPE, sorry, this needs to one, since interlink steps can be > 0 */
- for (int thisInterlinkStep = interlinkStepCount - 1; thisInterlinkStep > 0; thisInterlinkStep--) {
- /* Could do this by doing a calculation on length of each co-ordinate and just doing one read
- but doing it this way makes it easier in the future to make use of this data */
- lat = gbfgetint32(mps_file);
- lon = gbfgetint32(mps_file);
-
- if (gbfgetc(mps_file) == 1) { /* altitude validity */
- mps_altitude = gbfgetdbl(mps_file);
- } else {
- mps_altitude = unknown_alt;
- gbfseek(mps_file, 8, SEEK_CUR);
- }
- }
-
- gbfread(tbuf, 1, 1, mps_file); /* NULL */
-
- gbfread(tbuf, 4, 1, mps_file); /* link max lat */
- gbfread(tbuf, 4, 1, mps_file); /* link max lon */
- gbfread(tbuf, 9, 1, mps_file); /* link max alt validity + alt */
-
- gbfread(tbuf, 4, 1, mps_file); /* link min lat */
- gbfread(tbuf, 4, 1, mps_file); /* link min lon */
- gbfread(tbuf, 9, 1, mps_file); /* link min alt validity + alt */
-
- } /* while (trk_count--) */
-
- /* when the loop is done, there's still one waypoint to read with a small trailer */
- /* all we want is the waypoint name; lat, lon and alt are already set from above */
- mps_readstr(mps_file, wptname, sizeof(wptname));
-#ifdef MPS_DEBUG
- fprintf(stderr, "mps_route_r: reading final route waypoint %s\n", wptname);
-#endif
-
-
- mpsclass = gbfgetint32(mps_file); /* class */
- mps_readstr(mps_file, tbuf, sizeof(tbuf)); /* country */
-
- if ((mps_ver == 4) || (mps_ver == 5)) {
- gbfread(tbuf, 22, 1, mps_file); /* subclass data */
-
- /* This is a bit unpleasant. Routes have a variable length of
- data (min 22 bytes) terminated by a zero */
- do {
- gbfread(tbuf, 1, 1, mps_file);
- } while (tbuf[0] && !gbfeof(mps_file));
-
- /* The next thing is the unknown 0x03 0x00 .. 0x00 (18 bytes) */
- gbfread(tbuf, 18, 1, mps_file);
- } else {
- gbfread(tbuf, 17, 1, mps_file); /* subclass data */
- gbfread(tbuf, 18, 1, mps_file); /* unknown 0x00 0x03 0x00 .. 0x00 */
- }
-
- gbfread(tbuf, 5, 1, mps_file); /* 5 byte trailer */
- /* with MapSource routes, the real waypoint details are held as a separate waypoint, so copy from there
- if found because there is more info held in a real waypoint than in its route counterpart,
- e.g. the display symbol (aka icon)
- */
- tempWpt = find_waypt_by_name(wptname);
-
- if (tempWpt != nullptr) {
- thisWaypoint = new Waypoint(*tempWpt);
- } else {
- tempWpt = mps_find_wpt_q_by_name(&read_route_wpt_head, wptname);
-
- if (tempWpt != nullptr) {
- thisWaypoint = new Waypoint(*tempWpt);
- } else {
- /* should never reach here, but we do need a fallback position */
- thisWaypoint = new Waypoint;
- thisWaypoint->shortname = wptname;
- thisWaypoint->latitude = GPS_Math_Semi_To_Deg(lat);
- thisWaypoint->longitude = GPS_Math_Semi_To_Deg(lon);
- thisWaypoint->altitude = mps_altitude;
- }
- }
-
- route_add_wpt(rte_head, thisWaypoint);
-}
-
-/*
- * write out to file a route header
- * MRCB
- */
-static void
-mps_routehdr_w(gbfile* mps_file, int mps_ver, const route_head* rte)
-{
- char* rname;
- char hdr[20];
- char zbuf[20];
-
- time_t uniqueValue = 0;
-
- double maxlat=-90.0;
- double maxlon=-180.0;
- double minlat=90.0;
- double minlon=180.0;
- double maxalt=unknown_alt;
- double minalt=-unknown_alt;
-
- prevRouteWpt = nullptr; /* clear the stateful flag used to know when the start of route wpts happens */
-
- memset(zbuf, 0, sizeof(zbuf));
-
- /* total nodes (waypoints) this route */
- unsigned int rte_datapoints = 0;
- int allWptNameLengths = 0;
-
- //if (rte->waypoint_list.next) { /* this test doesn't do what I want i.e test if this is a valid route - treat as a placeholder for now */
- if (true) {
- foreach (const Waypoint* testwpt, rte->waypoint_list) {
- if (rte_datapoints == 0) {
- uniqueValue = testwpt->GetCreationTime().toTime_t();
- }
- if (testwpt->latitude > maxlat) {
- maxlat = testwpt->latitude;
- }
- if (testwpt->latitude < minlat) {
- minlat = testwpt->latitude;
- }
- if (testwpt->longitude > maxlon) {
- maxlon = testwpt->longitude;
- }
- if (testwpt->longitude < minlon) {
- minlon = testwpt->longitude;
- }
- if (testwpt->altitude != unknown_alt) {
- if ((testwpt->altitude > maxalt) ||
- (maxalt == unknown_alt)) {
- maxalt = testwpt->altitude;
- }
- if ((testwpt->altitude < minalt) ||
- (minalt == -unknown_alt)) {
- minalt = testwpt->altitude;
- }
- }
-
- QString src;
- if (!testwpt->description.isEmpty()) {
- src = testwpt->description;
- }
- if (!testwpt->notes.isEmpty()) {
- src = testwpt->notes;
- }
- QString ident = global_opts.synthesize_shortnames ?
- mkshort(mkshort_handle, src) :
- CSTRc(testwpt->shortname);
- allWptNameLengths += ident.length() + 1;
-
- rte_datapoints++;
- }
-
- if (uniqueValue == 0) {
- uniqueValue = current_time().toTime_t();
- }
-
- /* route name */
- if (rte->rte_name.isEmpty()) {
- sprintf(hdr, "Route%04x", (unsigned) uniqueValue);
- rname = xstrdup(hdr);
- } else {
- rname = xstrdup(rte->rte_name);
- }
-
- int rname_len = strlen(rname);
- unsigned int reclen = rname_len + 42; /* "T" (1) + strlen(tname) + NULL (1) + autoname flag (2) +
- route lat lon max (2x4) + route max alt (9) +
- route lat lon min (2x4) + route min alt (9) +
- num route datapoints value (4) */
-
- /* V3 - each waypoint: waypoint name + NULL (1) + class (4) + country + NULL (1) +
- subclass (17) + unknown (18) */
- /* V4,5 - each waypoint: waypoint name + NULL (1) + class (4) + country + NULL (1) +
- subclass (18) + unknown (4) + unknown (19) */
- /* V* - each route link: 0x00000002 (4) + end 1 lat (4) + end 1 lon (4) + end 1 alt (9) +
- end 2 lat (4) + end 2 lon (4) + end 2 alt (9) + NULL (1) +
- link max lat (4) + link max lon (4) + link max alt (9) +
- link min lat (4) + link min lon (4) + link min alt (9) */
-
- if ((mps_ver == 4) || (mps_ver == 5)) {
- reclen += allWptNameLengths + rte_datapoints * 46 +
- (rte_datapoints - 1) * 73 + 4; /* link details plus overall trailing bytes */
- } else {
- reclen += allWptNameLengths + rte_datapoints * 40 +
- (rte_datapoints - 1) * 73 + 4; /* link details plus overall trailing bytes */
- }
-
- gbfputint32(reclen, mps_file);
- gbfputc('R', mps_file);
- gbfwrite(rname, 1, rname_len, mps_file);
-
- xfree(rname);
-
- hdr[0] = 0; /* NULL of string termination */
- hdr[1] = 0; /* don't autoname */
- hdr[2] = 0; /* MSB of don't autoname */
- gbfwrite(hdr, 3, 1, mps_file); /* NULL string terminator + route autoname flag */
-
- int lat = GPS_Math_Deg_To_Semi(maxlat);
- int lon = GPS_Math_Deg_To_Semi(maxlon);
-
- gbfputint32(lat, mps_file);
- gbfputint32(lon, mps_file);
-
- if (maxalt == unknown_alt) {
- gbfwrite(zbuf, 9, 1, mps_file);
- } else {
- gbfputc(1, mps_file);
- gbfputdbl(maxalt, mps_file);
- }
-
- lat = GPS_Math_Deg_To_Semi(minlat);
- lon = GPS_Math_Deg_To_Semi(minlon);
-
- gbfputint32(lat, mps_file);
- gbfputint32(lon, mps_file);
-
- if (minalt == -unknown_alt) {
- gbfwrite(zbuf, 9, 1, mps_file);
- } else {
- gbfputc(1, mps_file);
- gbfputdbl(minalt, mps_file);
- }
-
- gbfputint32(rte_datapoints, mps_file);
- }
-}
-
-static void
-mps_routehdr_w_wrapper(const route_head* rte)
-{
- mps_routehdr_w(mps_file_out, mps_ver_out, rte);
-}
-
-
-/*
- * write out to file a route datapoint
- * MRCB
- */
-static void
-mps_routedatapoint_w(gbfile* mps_file, int mps_ver, const Waypoint* rtewpt)
-{
- char zbuf[20];
- char ffbuf[20];
-
- int maxlat;
- int maxlon;
- int minlat;
- int minlon;
- double maxalt=unknown_alt;
- double minalt=-unknown_alt;
-
- memset(zbuf, 0, sizeof(zbuf));
- memset(ffbuf, 0xff, sizeof(ffbuf));
-
- if (prevRouteWpt != nullptr) {
- /* output the route link details */
- int reclen = 2;
- gbfputint32(reclen, mps_file);
-
- /* output end point 1 */
- int lat = GPS_Math_Deg_To_Semi(prevRouteWpt->latitude);
- int lon = GPS_Math_Deg_To_Semi(prevRouteWpt->longitude);
-
- gbfputint32(lat, mps_file);
- gbfputint32(lon, mps_file);
-
- double mps_altitude = prevRouteWpt->altitude;
- if (mps_altitude == unknown_alt) {
- gbfwrite(zbuf, 9, 1, mps_file);
- } else {
- gbfputc(1, mps_file);
- gbfputdbl(mps_altitude, mps_file);
- }
-
- /* output end point 2 */
- lat = GPS_Math_Deg_To_Semi(rtewpt->latitude);
- lon = GPS_Math_Deg_To_Semi(rtewpt->longitude);
-
- gbfputint32(lat, mps_file);
- gbfputint32(lon, mps_file);
-
- mps_altitude = rtewpt->altitude;
- if (mps_altitude == unknown_alt) {
- gbfwrite(zbuf, 9, 1, mps_file);
- } else {
- gbfputc(1, mps_file);
- gbfputdbl(mps_altitude, mps_file);
- }
-
- if (rtewpt->latitude > prevRouteWpt->latitude) {
- maxlat = GPS_Math_Deg_To_Semi(rtewpt->latitude);
- minlat = GPS_Math_Deg_To_Semi(prevRouteWpt->latitude);
- } else {
- minlat = GPS_Math_Deg_To_Semi(rtewpt->latitude);
- maxlat = GPS_Math_Deg_To_Semi(prevRouteWpt->latitude);
- }
-
- if (rtewpt->longitude > prevRouteWpt->longitude) {
- maxlon = GPS_Math_Deg_To_Semi(rtewpt->longitude);
- minlon = GPS_Math_Deg_To_Semi(prevRouteWpt->longitude);
- } else {
- minlon = GPS_Math_Deg_To_Semi(rtewpt->longitude);
- maxlon = GPS_Math_Deg_To_Semi(prevRouteWpt->longitude);
- }
-
- if (rtewpt->altitude != unknown_alt) {
- maxalt = rtewpt->altitude;
- }
- if (rtewpt->altitude != unknown_alt) {
- minalt = rtewpt->altitude;
- }
- if (prevRouteWpt->altitude != unknown_alt) {
- if ((prevRouteWpt->altitude > maxalt) ||
- (maxalt == unknown_alt)) {
- maxalt = prevRouteWpt->altitude;
- }
- if ((prevRouteWpt->altitude < minalt) ||
- (minalt == -unknown_alt)) {
- minalt = prevRouteWpt->altitude;
- }
- }
-
- gbfwrite(zbuf, 1, 1, mps_file);
-
- /* output max coords of the link */
- gbfputint32(maxlat, mps_file);
- gbfputint32(maxlon, mps_file);
-
- if (maxalt == unknown_alt) {
- gbfwrite(zbuf, 9, 1, mps_file);
- } else {
- gbfputc(1, mps_file);
- gbfputdbl(maxalt, mps_file);
- }
-
- /* output min coords of the link */
- gbfputint32(minlat, mps_file);
- gbfputint32(minlon, mps_file);
-
- if (minalt == -unknown_alt) {
- gbfwrite(zbuf, 9, 1, mps_file);
- } else {
- gbfputc(1, mps_file);
- gbfputdbl(minalt, mps_file);
- }
-
- }
-
- QString src;
- if (!rtewpt->description.isEmpty()) {
- src = rtewpt->description;
- }
- if (!rtewpt->notes.isEmpty()) {
- src = rtewpt->notes;
- }
- QString ident = global_opts.synthesize_shortnames ?
- mkshort(mkshort_handle, src) :
- CSTRc(rtewpt->shortname);
-
- gbfputs(ident, mps_file);
- gbfwrite(zbuf, 1, 1, mps_file); /* NULL termination to ident */
-
- Waypoint* wptfound = mps_find_wpt_q_by_name(&written_route_wpt_head, ident);
- if (wptfound != nullptr) {
- zbuf[0] = (char)MPSHIDDENROUTEWPTCLASS;
- } else {
- zbuf[0] = (char)MPSDEFAULTWPTCLASS;
- }
- gbfwrite(zbuf, 4, 1, mps_file); /* class */
-
- zbuf[0]=0;
- gbfwrite(zbuf, 1, 1, mps_file); /* country - i.e. empty string */
-
- if ((mps_ver == 4) || (mps_ver == 5)) {
- gbfwrite(zbuf, 4, 1, mps_file); /* subclass part 1 */
- gbfwrite(ffbuf, 12, 1, mps_file); /* subclass part 2 */
- gbfwrite(zbuf, 2, 1, mps_file); /* subclass part 3 */
- gbfwrite(ffbuf, 4, 1, mps_file); /* unknown */
-
- gbfwrite(zbuf, 1, 1, mps_file);
- gbfputc(3, mps_file);
- gbfwrite(zbuf, 17, 1, mps_file);
- } else {
- gbfwrite(zbuf, 8, 1, mps_file); /* subclass part 1 */
- gbfwrite(ffbuf, 8, 1, mps_file); /* subclass part 2 */
- gbfwrite(zbuf, 1, 1, mps_file); /* subclass part 3 */
-
- /* unknown */
- gbfwrite(zbuf, 1, 1, mps_file);
- gbfputc(3, mps_file);
- gbfwrite(zbuf, 16, 1, mps_file);
- }
-
- prevRouteWpt = rtewpt;
-}
-
-static void
-mps_routedatapoint_w_wrapper(const Waypoint* rte)
-{
- mps_routedatapoint_w(mps_file_out, mps_ver_out, rte);
-}
-
-
-/*
- * write out to file a route trailer
- * MRCB
- */
-static void
-mps_routetrlr_w(gbfile* mps_file, int mps_ver, const route_head* /* rte */)
-{
- char hdr[2];
- int value = 0;
-
- (void)mps_ver;
- hdr[0] = 1;
-
- //if (rte->waypoint_list.next) { /* this test doesn't do what I want i.e test if this is a valid route - treat as a placeholder for now */
- if (true) {
- gbfwrite(&value, 4, 1, mps_file);
- gbfwrite(hdr, 1, 1, mps_file);
- }
-}
-
-static void
-mps_routetrlr_w_wrapper(const route_head* rte)
-{
- mps_routetrlr_w(mps_file_out, mps_ver_out, rte);
-}
-
-
-/*
- * read in from file a track record
- * MRCB
- */
-static void
-mps_track_r(gbfile* mps_file, int mps_ver, route_head** trk)
-{
- int lat;
- int lon;
-
- int dateTime = 0;
- route_head* track_head;
- int trk_count;
-
- Waypoint* thisWaypoint;
- double mps_altitude = unknown_alt;
- double mps_depth = unknown_alt;
-
- (void)mps_ver;
-
- QString trkname = gbfgetcstr(mps_file);
-#ifdef MPS_DEBUG
- fprintf(stderr, "mps_track_r: reading track %s\n", trkname);
-#endif
-
- (void) gbfgetc(mps_file); /* display flag */
- (void) gbfgetint32(mps_file); /* colour */
-
- trk_count = gbfgetint32(mps_file); /* number of datapoints in tracklog */
-
- /* I don't know, but perhaps it's valid to have a track with no waypoints */
- /* Seems dumb, but truth is stranger than fiction. Of course, it could be */
- /* that there are more than MAXINT / 2 waypoints, yeah sure */
- /* Allow the caller the perform the file resync caused by bombing out early */
- if (trk_count < 0) {
- return;
- }
-#ifdef MPS_DEBUG
- fprintf(stderr, "mps_track_r: there are %d track waypoints\n", trk_count);
-#endif
-
- track_head = new route_head;
- track_head->rte_name = trkname;
- track_add_head(track_head);
- *trk = track_head;
-
- while (trk_count--) {
-
- lat = gbfgetint32(mps_file);
- lon = gbfgetint32(mps_file);
-
- if (gbfgetc(mps_file) == 1) { /* altitude validity */
- mps_altitude = gbfgetdbl(mps_file);
- } else {
- mps_altitude = unknown_alt;
- gbfseek(mps_file, 8, SEEK_CUR);
- }
-
- if (gbfgetc(mps_file) == 1) { /* date/time validity */
- dateTime = gbfgetint32(mps_file);
- } else {
- (void) gbfgetint32(mps_file);
- }
-
- if (gbfgetc(mps_file) == 1) { /* depth validity */
- mps_depth = gbfgetdbl(mps_file);
- } else {
- mps_depth = unknown_alt;
- gbfseek(mps_file, 8, SEEK_CUR);
- }
-
- thisWaypoint = new Waypoint;
- thisWaypoint->latitude = GPS_Math_Semi_To_Deg(lat);
- thisWaypoint->longitude = GPS_Math_Semi_To_Deg(lon);
- thisWaypoint->SetCreationTime(dateTime);
- thisWaypoint->altitude = mps_altitude;
- if (mps_depth != unknown_alt) {
- WAYPT_SET(thisWaypoint, depth, mps_depth);
- }
- track_add_wpt(track_head, thisWaypoint);
-
- } /* while (trk_count--) */
-
-
-}
-
-/*
- * write out to file a tracklog header
- * MRCB
- */
-static void
-mps_trackhdr_w(gbfile* mps_file, int mps_ver, const route_head* trk)
-{
- unsigned int colour = 0; /* unknown colour */
- char* tname;
- char hdr[20];
- time_t uniqueValue = 0;
-
- (void)mps_ver;
-
- /* total nodes (waypoints) this track */
- unsigned int trk_datapoints = 0;
- //if (trk->waypoint_list.next) { /* this test doesn't do what I want i.e test if this is a valid track - treat as a placeholder for now */
- if (true) {
- foreach (const Waypoint* testwpt, trk->waypoint_list) {
- if (trk_datapoints == 0) {
- uniqueValue = testwpt->GetCreationTime().toTime_t();
- }
- trk_datapoints++;
- }
-
- if (uniqueValue == 0) {
- uniqueValue = current_time().toTime_t();
- }
-
- /* track name */
- if (trk->rte_name.isEmpty()) {
- sprintf(hdr, "Track%04x", (unsigned) uniqueValue);
- tname = xstrdup(hdr);
- } else {
- tname = xstrdup(trk->rte_name);
- }
-
- int tname_len = strlen(tname);
- unsigned int reclen = tname_len + 11; /* "T" (1) + strlen(tname) + NULL (1) + display flag (1) + colour (4) +
- num track datapoints value (4) */
-
- reclen += (trk_datapoints * 31) - 1; /* lat (4) + lon (4) + alt (9) + date (5) + depth (9) ;*/
- /* -1 is because reclen starts from 0 which means a length of 1 */
- gbfputint32(reclen, mps_file);
- gbfputc('T', mps_file);
- gbfwrite(tname, 1, tname_len, mps_file);
-
- xfree(tname);
-
- hdr[0] = 0;
- hdr[1] = 1;
- gbfwrite(hdr, 2, 1, mps_file); /* NULL string terminator + display flag */
-
- gbfputint32(colour, mps_file);
-
- gbfputint32(trk_datapoints, mps_file);
- }
-
-}
-
-static void
-mps_trackhdr_w_wrapper(const route_head* trk)
-{
- mps_trackhdr_w(mps_file_out, mps_ver_out, trk);
-}
-
-
-/*
- * write out to file a tracklog datapoint
- * MRCB
- */
-static void
-mps_trackdatapoint_w(gbfile* mps_file, int mps_ver, const Waypoint* wpt)
-{
- time_t t = wpt->GetCreationTime().toTime_t();
- char zbuf[10];
-
- double mps_altitude = wpt->altitude;
- double mps_depth = unknown_alt;
-
- (void)mps_ver;
-
- int lat = GPS_Math_Deg_To_Semi(wpt->latitude);
- int lon = GPS_Math_Deg_To_Semi(wpt->longitude);
- if (WAYPT_HAS(wpt, depth) && mpsusedepth) {
- mps_depth = wpt->depth;
- }
-
- memset(zbuf, 0, sizeof(zbuf));
-
- gbfputint32(lat, mps_file);
- gbfputint32(lon, mps_file);
-
- if (mps_altitude == unknown_alt) {
- gbfwrite(zbuf, 9, 1, mps_file);
- } else {
- gbfputc(1, mps_file);
- gbfputdbl(mps_altitude, mps_file);
- }
-
- if (t > 0) { /* a valid time is assumed to > 0 */
- gbfputc(1, mps_file);
- gbfputint32(t, mps_file);
- } else {
- gbfwrite(zbuf, 5, 1, mps_file);
- }
-
- if (mps_depth == unknown_alt) {
- gbfwrite(zbuf, 9, 1, mps_file);
- } else {
- gbfputc(1, mps_file);
- gbfputdbl(mps_depth, mps_file);
- }
-}
-
-static void
-mps_trackdatapoint_w_wrapper(const Waypoint* wpt)
-{
- mps_trackdatapoint_w(mps_file_out, mps_ver_out, wpt);
-}
-
-
-static void
-mps_read()
-{
- Waypoint* wpt;
- route_head* rte;
- route_head* trk;
-
- char recType;
- int reclen;
- int morework;
- unsigned int mpsWptClass;
- long mpsFileInPos;
-
- mps_ver_in = 0; /* although initialised at declaration, what happens if there are two mapsource
- input files? */
- mps_fileHeader_r(mps_file_in, &mps_ver_in);
-
-#ifdef DUMP_ICON_TABLE
- printf("static icon_mapping_t garmin_icon_table[] = {\n");
-#endif
-
- morework = 1;
- while (morework && !gbfeof(mps_file_in)) {
-
- /* Read record length of next section */
- reclen = gbfgetint32(mps_file_in);
-
- if (reclen < 0) {
- fatal(MYNAME ": a record length read from the input file is invalid. \nEither the file is corrupt or unsupported.\n");
- }
-
- /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
- gbfread(&recType, 1, 1, mps_file_in);
- mpsFileInPos = gbftell(mps_file_in);
- switch (recType) {
- case 'W':
- /* Waypoint record */
- /* With routes, we need the waypoint info that reveals, for example, the symbol type */
- mps_waypoint_r(mps_file_in, mps_ver_in, &wpt, &mpsWptClass);
-
-#ifdef MPS_DEBUG
- fprintf(stderr,"Read a waypoint - %s\n", wpt->shortname);
-#endif
-
- if (gbftell(mps_file_in) != mpsFileInPos + reclen) {
- /* should junk this record and not save it since we're out of sync with the file */
- /* Should and how do we warn the user? */
-#ifdef MPS_DEBUG
- fprintf(stderr,"Lost sync with the file reading waypoint - %s\n", wpt->shortname);
-#endif
- gbfseek(mps_file_in, mpsFileInPos + reclen, SEEK_SET);
- delete wpt;
- } else {
- /* only add to the "real" list if a "user" waypoint otherwise add to the private list */
- if (mpsWptClass == MPSDEFAULTWPTCLASS) {
- waypt_add(wpt);
- } else {
- mps_wpt_q_add(&read_route_wpt_head, wpt);
- delete wpt;
- }
-#ifdef DUMP_ICON_TABLE
- printf("\t{ %4u, \"%s\" },\n", icon, wpt->shortname);
-#endif
- }
- break;
-
- case 'R':
- /* Route record */
- mps_route_r(mps_file_in, mps_ver_in, &rte);
- if (gbftell(mps_file_in) != mpsFileInPos + reclen) {
- /* should junk this record and not save it since we're out of sync with the file */
- /* Should and how do we warn the user? */
-#ifdef MPS_DEBUG
- fprintf(stderr,"Lost sync with the file reading route - %s\n", rte->rte_name);
-#endif
- gbfseek(mps_file_in, mpsFileInPos + reclen, SEEK_SET);
- }
- break;
-
- case 'T':
- /* Track record */
- mps_track_r(mps_file_in, mps_ver_in, &trk);
- if (gbftell(mps_file_in) != mpsFileInPos + reclen) {
- /* should junk this record and not save it since we're out of sync with the file */
- /* Should and how do we warn the user? */
-#ifdef MPS_DEBUG
- fprintf(stderr,"Lost sync with the file reading track - %s\n", trk->rte_name);
-#endif
- gbfseek(mps_file_in, mpsFileInPos + reclen, SEEK_SET);
- }
- break;
-
- case 'L':
- /* Map segment record */
- mps_mapsegment_r(mps_file_in, mps_ver_in);
- if (gbftell(mps_file_in) != mpsFileInPos + reclen) {
- /* should junk this record and not save it since we're out of sync with the file */
- /* Should and how do we warn the user? */
- gbfseek(mps_file_in, mpsFileInPos + reclen, SEEK_SET);
- }
- break;
-
- case 'V':
- /* Mapset record */
- mps_mapsetname_r(mps_file_in, mps_ver_in);
- /* Last record in the file */
- morework = 0;
- break;
- default:
- /* Unknown record type. Skip over it. */
- gbfseek(mps_file_in, reclen, SEEK_CUR);
- }
-
- } /* while (!gbfeof(mps_file_in)) */
-
-#ifdef DUMP_ICON_TABLE
- printf("\t{ -1, NULL },\n");
- printf("};\n");
-#endif
-
-
-}
-
-static void
-mps_write()
-{
- Waypoint* wpt;
- route_head* rte;
- route_head* trk;
-
- char recType = -1;
- int reclen;
- /* TODO: This kills a compiler warning but I'm not sure it's right */
- int reclen2 = 0;
- unsigned int tocopy;
- unsigned int block;
-
- unsigned int mpsWptClass;
-
- unsigned char copybuf[8192];
-
- int short_length = atoi(snlen);
-
- if (mpsmergeout) {
- /* need to skip over the merging header and test merge version */
- mps_fileHeader_r(mps_file_temp, &mps_ver_temp);
-
- if (mpsverout) {
- if (mps_ver_temp != atoi(mpsverout)) {
- /* Need to clean up after a junk version specified */
- /* close the real output file + renamed original output file */
- /* then delete the "real" file and rename the temporarily renamed file back */
- gbfclose(mps_file_temp);
- gbfclose(mps_file_out);
- QFile::remove(fin_name);
- QFile::rename(tempname, fin_name);
- fatal(MYNAME ": merge source version is %d, requested out version is %d\n", mps_ver_temp, atoi(mpsverout));
- }
- } else {
- mpsverout = (char*) xmalloc(10);
- sprintf(mpsverout,"%d", mps_ver_temp);
- }
- }
-
- if (mpsverout) {
- mps_ver_out = atoi(mpsverout);
- } else {
- mps_ver_out = 5;
- }
-
- mkshort_handle = mkshort_new_handle();
-
- setshort_length(mkshort_handle, short_length);
-
- if (snwhiteopt) {
- setshort_whitespace_ok(mkshort_handle, atoi(snwhiteopt));
- } else {
- setshort_whitespace_ok(mkshort_handle, 0);
- }
-
- mps_fileHeader_w(mps_file_out, mps_ver_out);
-
- /* .mps file order is wpts, rtes, trks then mapsets. If we've not been asked to write
- wpts, but we are merging, then read in the waypoints from the original file and
- write them out, prior to doing rtes.
- */
- /* if ((mpsmergeout) && (global_opts.objective != wptdata)) { */
- if ((mpsmergeout) && (! doing_wpts)) {
- while (!gbfeof(mps_file_temp)) {
-
- reclen2 = gbfgetint32(mps_file_temp);
-
- /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
- gbfread(&recType, 1, 1, mps_file_temp);
-
- if (recType == 'W') {
- gbfwrite(&reclen, 4, 1, mps_file_out); /* write out untouched */
- gbfwrite(&recType, 1, 1, mps_file_out);
-
- long tempFilePos = gbftell(mps_file_temp);
- /* need to read in the waypoint info only because later we may need to check for uniqueness
- since we're here because the user didn't request waypoints, this should be acceptable */
- mps_waypoint_r(mps_file_temp, mps_ver_temp, &wpt, &mpsWptClass);
- mps_wpt_q_add(&written_wpt_head, wpt);
- delete wpt;
- /* now return to the start of the waypoint data to do a "clean" copy */
- gbfseek(mps_file_temp, tempFilePos, SEEK_SET);
-
- /* copy the data using a "reasonably" sized buffer */
- for (tocopy = reclen2; tocopy > 0; tocopy -= block) {
- block = (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy);
- gbfread(copybuf, block, 1, mps_file_temp);
- gbfwrite(copybuf, block, 1, mps_file_out);
- }
- } else {
- break;
- }
- } /* while (!gbfeof(mps_file_temp)) */
- } /* if (mpsmergeout) */
-
- /* irrespective of merging, now write out any waypoints */
- /* if (global_opts.objective == wptdata) { */
- if (doing_wpts) {
-
- if (mpsmergeout) {
- /* since we're processing waypoints, we should read in from whatever version and write out */
- /* in the selected version */
- while (!gbfeof(mps_file_temp)) {
-
- reclen2 = gbfgetint32(mps_file_temp);
-
- /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
- gbfread(&recType, 1, 1, mps_file_temp);
-
- if (recType == 'W') {
- /* need to be careful that we aren't duplicating a wpt defined from elsewhere */
- mps_waypoint_r(mps_file_temp, mps_ver_temp, &wpt, &mpsWptClass);
- if (mpsWptClass == MPSDEFAULTWPTCLASS) {
- waypt_add(wpt);
- } else {
- delete wpt;
- }
- } else {
- break;
- }
- }
- }
- waypt_disp_all(mps_waypoint_w_unique_wrapper);
- }
-
- /* prior to writing any tracks as requested, if we're doing a merge, read in the rtes
- from the original file and then write them out, ready for tracks to follow
- */
-
- /* if ((mpsmergeout) && (global_opts.objective != rtedata)) { */
- if ((mpsmergeout) && (! doing_rtes)) {
- while (!gbfeof(mps_file_temp)) {
-
- /* this might all fail if the relevant waypoints haven't been written */
- if (recType == 'R') {
- gbfwrite(&reclen, 4, 1, mps_file_out); /* write out untouched */
- gbfwrite(&recType, 1, 1, mps_file_out);
-
- /* copy the data using a "reasonably" sized buffer */
- for (tocopy = reclen2; tocopy > 0; tocopy -= block) {
- block = (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy);
- gbfread(copybuf, block, 1, mps_file_temp);
- gbfwrite(copybuf, block, 1, mps_file_out);
- }
- } else {
- break;
- }
- reclen2 = gbfgetint32(mps_file_temp);
-
- /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
- gbfread(&recType, 1, 1, mps_file_temp);
-
- } /* while (!gbfeof(mps_file_temp)) */
- } /* if (mpsmergeout) */
-
- /* routes are next in the wpts, rtes, trks, mapset sequence */
- /* if (global_opts.objective == rtedata) { */
- if (doing_rtes) {
-
- if (mpsmergeout) {
- /* since we're processing routes, we should read in from whatever version and write out */
- /* in the selected version */
- while (!gbfeof(mps_file_temp)) {
-
- if (recType == 'R') {
- mps_route_r(mps_file_temp, mps_ver_temp, &rte);
- } else {
- break;
- }
-
- reclen2 = gbfgetint32(mps_file_temp);
-
- /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
- gbfread(&recType, 1, 1, mps_file_temp);
- }
- }
- /* need to make sure there is a "real" waypoint for each route waypoint
- Need to be careful about creating duplicate wpts as MapSource chokes on these
- so, if the user requested waypoints to be output too, then write the route
- waypoints only if unique in the total list of waypoints ("real" and route derived)
- If the user didn't request waypoints to be output, then output the route derived
- waypoints without consideration for uniqueness for "real" waypoints that haven't
- been output (phew!)
- */
- route_disp_all(nullptr, nullptr, mps_route_wpt_w_unique_wrapper);
-
- route_disp_all(mps_routehdr_w_wrapper, mps_routetrlr_w_wrapper, mps_routedatapoint_w_wrapper);
- }
-
- /* If merging but we haven't been requested to write out tracks, then read in tracks from
- the original file and write these out prior to any mapset writes later on
- */
- /* if ((mpsmergeout) && (global_opts.objective != trkdata)) { */
- if ((mpsmergeout) && (! doing_trks)) {
- while (!gbfeof(mps_file_temp)) {
-
- if (recType == 'T') {
- gbfwrite(&reclen, 4, 1, mps_file_out); /* write out untouched */
- gbfwrite(&recType, 1, 1, mps_file_out);
-
- /* copy the data using a "reasonably" sized buffer */
- for (tocopy = reclen2; tocopy > 0; tocopy -= block) {
- block = (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy);
- gbfread(copybuf, block, 1, mps_file_temp);
- gbfwrite(copybuf, block, 1, mps_file_out);
- }
- } else {
- break;
- }
- reclen2 = gbfgetint32(mps_file_temp);
-
- /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
- gbfread(&recType, 1, 1, mps_file_temp);
-
- } /* while (!gbfeof(mps_file_temp)) */
- } /* if (mpsmergeout) */
-
- /* tracks are next in the wpts, rte, trks, mapset sequence in .mps files */
- /* if (global_opts.objective == trkdata) { */
- if (doing_trks) {
- if (mpsmergeout) {
- /* since we're processing tracks, we should read in from whatever version and write out
- in the selected version */
- while (!gbfeof(mps_file_temp)) {
-
- if (recType == 'T') {
- mps_track_r(mps_file_temp, mps_ver_temp, &trk);
- } else {
- break;
- }
-
- reclen2 = gbfgetint32(mps_file_temp);
-
- /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
- gbfread(&recType, 1, 1, mps_file_temp);
- }
- }
- track_disp_all(mps_trackhdr_w_wrapper, nullptr, mps_trackdatapoint_w_wrapper);
- }
-
- if (mpsmergeout) {
- /* should now be reading a either a map segment or a mapset - since we would write out an empty one,
- let's use the one from the merge file which may well have decent data in */
- for (;;) {
- gbfwrite(&reclen, 4, 1, mps_file_out); /* write out untouched */
- gbfwrite(&recType, 1, 1, mps_file_out);
-
- /* copy the data using a "reasonably" sized buffer */
- for (tocopy = reclen2; tocopy > 0; tocopy -= block) {
- block = (tocopy > sizeof(copybuf) ? sizeof(copybuf) : tocopy);
- gbfread(copybuf, block, 1, mps_file_temp);
- gbfwrite(copybuf, block, 1, mps_file_out);
- }
-
- if (recType != 'V') {
- reclen2 = gbfgetint32(mps_file_temp);
-
- /* Read the record type "flag" in - using gbfread in case in the future need more than one char */
- gbfread(&recType, 1, 1, mps_file_temp);
- } else {
- break;
- }
- }
-
- } else {
- mps_mapsetname_w(mps_file_out, mps_ver_out);
- }
-
- mkshort_del_handle(&mkshort_handle);
-
-}
-
-ff_vecs_t mps_vecs = {
- ff_type_file,
- FF_CAP_RW_ALL,
- mps_rd_init,
- mps_wr_init,
- mps_rd_deinit,
- mps_wr_deinit,
- mps_read,
- mps_write,
- nullptr,
- &mps_args,
- CET_CHARSET_MS_ANSI, 0, /* CET-REVIEW */
- NULL_POS_OPS,
- nullptr,
-};
/*
Read Netstumbler data files.
- Copyright (C) 2004, 2005 Robert Lipe, robertlipe+source@gpsbabel.org and
+ Copyright (C) 2004-2020 Robert Lipe, robertlipe+source@gpsbabel.org and
John Temples; gpsns@xargs.com
This program is free software; you can redistribute it and/or modify
*/
-#include <cctype> // for isspace
-#include <cstdio> // for snprintf
-#include <cstdlib> // for atoi, atof, qsort, strtol
-#include <cstring> // for strcpy, strlen, memset, strncmp, strstr
-#include <ctime> // for mktime
-
-#include <QtCore/QString> // for QString
-#include <QtCore/QtGlobal> // for foreach
-
-#include "defs.h"
-#include "cet_util.h" // for cet_convert_init
-#include "csv_util.h" // for csv_lineparse
-#include "gbfile.h" // for gbfclose, gbfgetstr, gbfopen, gbfile
-
+#include <QtCore/QDate> // for QDate
+#include <QtCore/QDateTime> // for QDateTime
+#include <QtCore/QString> // for QString
+#include <QtCore/QTime> // for QTime
+#include <QtCore/QVector> // for QVector
+#include <QtCore/Qt> // for UTC
+#include <cctype> // for isspace
+#include <cstdio> // for snprintf
+#include <cstdlib> // for atof, atoi, qsort, strtol
+#include <cstring> // for strcpy, strlen, strncmp, strstr
+#include "cet_util.h" // for cet_convert_init
+#include "csv_util.h" // for csv_lineparse
+#include "defs.h" // for arglist_t, Waypoint, ff_cap, WaypointList, ff_cap_none, ddmm2degrees, ARG_NOMINMAX, ARGTYPE_STRING, ff_cap_read, get_crc32, lrtrim, waypt_add, xfree, xmalloc, ff_type_file, ARGTYPE_BOOL, CET_CHARSET_ASCII, CET_CHARSET_UTF8, CSTR, NULL_POS_OPS, ff_vecs_t
+#include "gbfile.h" // for gbfclose, gbfgetstr, gbfopen, gbfile
static gbfile* file_in;
static char* nseicon = nullptr;
int stealth_num = 0, whitespace_num = 0;
long flags = 0;
int speed = 0, channel = 0;
- struct tm tm;
int line = 0;
WaypointList tmp_waypt_list;
-
- memset(&tm, 0, sizeof(tm));
+ QDate date;
+ QTime time;
while ((ibuf = gbfgetstr(file_in))) {
int len;
int stealth = 0;
+
if ((line++ == 0) && file_in->unicode) {
cet_convert_init(CET_CHARSET_UTF8, 1);
}
if (ibuf[0] == '#') {
if (strncmp(&ibuf[2], "$DateGMT:", 9) == 0) {
- tm.tm_year = atoi(&ibuf[12]) - 1900;
- tm.tm_mon = atoi(&ibuf[17]) - 1;
- tm.tm_mday = atoi(&ibuf[20]);
+ date = QDate::fromString(ibuf + 12, "yyyy-MM-dd");
}
/*
break;
case 5: /* time */
- tm.tm_hour = atoi(field);
- tm.tm_min = atoi(&field[3]);
- tm.tm_sec = atoi(&field[6]);
+ time = QTime::fromString(field, "hh:mm:ss");
break;
case 8: /* flags */
wpt_tmp->description = desc;
wpt_tmp->longitude = lon;
wpt_tmp->latitude = lat;
- wpt_tmp->SetCreationTime(mktime(&tm));
+ wpt_tmp->SetCreationTime(QDateTime(date, time, Qt::UTC));
tmp_waypt_list.waypt_add(wpt_tmp);
}
garmin_g1000 csv Garmin G1000 datalog input filter file
glogbook xml Garmin Logbook XML
gdb gdb Garmin MapSource - gdb
-mapsource mps Garmin MapSource - mps
garmin_txt txt Garmin MapSource - txt (tab delimited)
pcx pcx Garmin PCX5
garmin_poi Garmin POI database
file garmin_g1000 csv Garmin G1000 datalog input filter file
file glogbook xml Garmin Logbook XML
file gdb gdb Garmin MapSource - gdb
-file mapsource mps Garmin MapSource - mps
file garmin_txt txt Garmin MapSource - txt (tab delimited)
file pcx pcx Garmin PCX5
file garmin_poi Garmin POI database
file --rw-- garmin_g1000 csv Garmin G1000 datalog input filter file
file --rw-- glogbook xml Garmin Logbook XML
file rwrwrw gdb gdb Garmin MapSource - gdb
-file rwrwrw mapsource mps Garmin MapSource - mps
file rwrwrw garmin_txt txt Garmin MapSource - txt (tab delimited)
file rwrwrw pcx pcx Garmin PCX5
file rw---- garmin_poi Garmin POI database
option gdb roadbook Include major turn points (with description) from calculated route boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_gdb.html#fmt_gdb_o_roadbook
-file rwrwrw mapsource mps Garmin MapSource - mps mapsource
- https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mapsource.html
-option mapsource snlen Length of generated shortnames integer 10 1 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mapsource.html#fmt_mapsource_o_snlen
-
-option mapsource snwhite Allow whitespace synth. shortnames boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mapsource.html#fmt_mapsource_o_snwhite
-
-option mapsource mpsverout Version of mapsource file to generate (3,4,5) integer https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mapsource.html#fmt_mapsource_o_mpsverout
-
-option mapsource mpsmergeout Merge output with existing file boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mapsource.html#fmt_mapsource_o_mpsmergeout
-
-option mapsource mpsusedepth Use depth values on output (default is ignore) boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mapsource.html#fmt_mapsource_o_mpsusedepth
-
-option mapsource mpsuseprox Use proximity values on output (default is ignore) boolean https://www.gpsbabel.org/WEB_DOC_DIR/fmt_mapsource.html#fmt_mapsource_o_mpsuseprox
-
file rwrwrw garmin_txt txt Garmin MapSource - txt (tab delimited) garmin_txt
https://www.gpsbabel.org/WEB_DOC_DIR/fmt_garmin_txt.html
option garmin_txt date Read/Write date format (i.e. yyyy/mm/dd) string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_garmin_txt.html#fmt_garmin_txt_o_date
ver Version of gdb file to generate (1..3)
via (0/1) Drop route points that do not have an equivalent w
roadbook (0/1) Include major turn points (with description) from
- mapsource Garmin MapSource - mps
- snlen Length of generated shortnames
- snwhite (0/1) Allow whitespace synth. shortnames
- mpsverout Version of mapsource file to generate (3,4,5)
- mpsmergeout (0/1) Merge output with existing file
- mpsusedepth (0/1) Use depth values on output (default is ignore)
- mpsuseprox (0/1) Use proximity values on output (default is ignore)
garmin_txt Garmin MapSource - txt (tab delimited)
date Read/Write date format (i.e. yyyy/mm/dd)
datum GPS datum (def. WGS 84)
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<gpx version="1.0" creator="GPSBabel - https://www.gpsbabel.org" xmlns="http://www.topografix.com/GPX/1/0">
+ <time>1970-01-01T00:00:00Z</time>
+ <bounds minlat="47.702875000" minlon="-91.015786700" maxlat="47.718261700" maxlon="-90.997521700"/>
+ <wpt lat="47.711118300" lon="-91.012175000">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>linksys</name>
+ <cmt>11 Mbps/Ch 6/0f:06:25:77:0d:1f</cmt>
+ <desc>11 Mbps/Ch 6/0f:06:25:77:0d:1f</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.710885000" lon="-91.012061700">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>default</name>
+ <cmt>0 Mbps/Ch 6/0f:05:5d:fa:f3:34</cmt>
+ <desc>0 Mbps/Ch 6/0f:05:5d:fa:f3:34</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.709603300" lon="-91.014330000">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>Stealth/1</name>
+ <cmt>11 Mbps/Ch 6/0f:40:96:44:c0:cc</cmt>
+ <desc>11 Mbps/Ch 6/0f:40:96:44:c0:cc</desc>
+ <sym>Red Diamond</sym>
+ </wpt>
+ <wpt lat="47.708885000" lon="-91.014668300">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>msu88</name>
+ <cmt>11 Mbps/Ch 6/0f:0c:41:bc:2a:8c</cmt>
+ <desc>11 Mbps/Ch 6/0f:0c:41:bc:2a:8c</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.707715000" lon="-91.015133300">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>linksys/3</name>
+ <cmt>11 Mbps/Ch 6/0f:06:25:a4:77:2e</cmt>
+ <desc>11 Mbps/Ch 6/0f:06:25:a4:77:2e</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.707286700" lon="-91.015263300">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>default/9</name>
+ <cmt>54 Mbps/Ch 6/0f:0d:88:8d:16:4f</cmt>
+ <desc>54 Mbps/Ch 6/0f:0d:88:8d:16:4f</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.706951700" lon="-91.015313300">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>silicon</name>
+ <cmt>11 Mbps/Ch 6/0f:30:bd:c1:3b:16</cmt>
+ <desc>11 Mbps/Ch 6/0f:30:bd:c1:3b:16</desc>
+ <sym>Red Square</sym>
+ </wpt>
+ <wpt lat="47.706610000" lon="-91.015368300">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>purnet</name>
+ <cmt>54 Mbps/Ch 6/0f:0c:41:ab:45:66</cmt>
+ <desc>54 Mbps/Ch 6/0f:0c:41:ab:45:66</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.706678300" lon="-91.015786700">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>Harvey</name>
+ <cmt>11 Mbps/Ch 8/0f:0d:88:1e:a5:6e</cmt>
+ <desc>11 Mbps/Ch 8/0f:0d:88:1e:a5:6e</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.706655000" lon="-91.013636700">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>X6604</name>
+ <cmt>11 Mbps/Ch 6/0f:a0:c5:69:65:10</cmt>
+ <desc>11 Mbps/Ch 6/0f:a0:c5:69:65:10</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.706760000" lon="-91.013390000">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>Scott</name>
+ <cmt>54 Mbps/Ch 10/0f:0d:93:88:3f:c1</cmt>
+ <desc>54 Mbps/Ch 10/0f:0d:93:88:3f:c1</desc>
+ <sym>Red Square</sym>
+ </wpt>
+ <wpt lat="47.707058300" lon="-91.012893300">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>NETGEAR</name>
+ <cmt>11 Mbps/Ch 11/0f:09:5b:6e:59:90</cmt>
+ <desc>11 Mbps/Ch 11/0f:09:5b:6e:59:90</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.706996700" lon="-91.012986700">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>Stealth/2</name>
+ <cmt>54 Mbps/Ch 5/00:05:5d:fb:02:bf</cmt>
+ <desc>54 Mbps/Ch 5/00:05:5d:fb:02:bf</desc>
+ <sym>Red Diamond</sym>
+ </wpt>
+ <wpt lat="47.706230000" lon="-91.011806700">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>cones</name>
+ <cmt>2 Mbps/Ch 6/0f:40:96:25:a2:b1</cmt>
+ <desc>2 Mbps/Ch 6/0f:40:96:25:a2:b1</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.702875000" lon="-91.008276700">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>default/10</name>
+ <cmt>54 Mbps/Ch 6/0f:0f:3d:00:d2:3f</cmt>
+ <desc>54 Mbps/Ch 6/0f:0f:3d:00:d2:3f</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.711835000" lon="-91.010883300">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>McKee</name>
+ <cmt>54 Mbps/Ch 3/0f:0c:41:74:6b:96</cmt>
+ <desc>54 Mbps/Ch 3/0f:0c:41:74:6b:96</desc>
+ <sym>Red Square</sym>
+ </wpt>
+ <wpt lat="47.711730000" lon="-91.010935000">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>airport</name>
+ <cmt>54 Mbps/Ch 10/0f:0a:95:f2:aa:0e</cmt>
+ <desc>54 Mbps/Ch 10/0f:0a:95:f2:aa:0e</desc>
+ <sym>Red Square</sym>
+ </wpt>
+ <wpt lat="47.711638300" lon="-91.010993300">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>merv</name>
+ <cmt>11 Mbps/Ch 6/0f:06:25:f0:e0:85</cmt>
+ <desc>11 Mbps/Ch 6/0f:06:25:f0:e0:85</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.710971700" lon="-91.011308300">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>home network</name>
+ <cmt>54 Mbps/Ch 6/0f:0f:66:2d:d0:bf</cmt>
+ <desc>54 Mbps/Ch 6/0f:0f:66:2d:d0:bf</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.710886700" lon="-91.011345000">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>Whitespace/1</name>
+ <cmt>11 Mbps/Ch 1/0f:02:2d:2b:81:cf</cmt>
+ <desc>11 Mbps/Ch 1/0f:02:2d:2b:81:cf</desc>
+ <sym>Red Square</sym>
+ </wpt>
+ <wpt lat="47.710771700" lon="-91.011556700">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>wifi</name>
+ <cmt>2 Mbps/Ch 6/0f:40:96:43:5b:9d</cmt>
+ <desc>2 Mbps/Ch 6/0f:40:96:43:5b:9d</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.714478300" lon="-91.013976700">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>dsppower</name>
+ <cmt>54 Mbps/Ch 6/0f:06:25:f7:6c:c9</cmt>
+ <desc>54 Mbps/Ch 6/0f:06:25:f7:6c:c9</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.714456700" lon="-91.014010000">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>linksys/4</name>
+ <cmt>11 Mbps/Ch 6/0f:0c:41:3e:1a:e8</cmt>
+ <desc>11 Mbps/Ch 6/0f:0c:41:3e:1a:e8</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.718261700" lon="-90.998576700">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>CAMELOT</name>
+ <cmt>11 Mbps/Ch 6/0f:06:25:05:24:3d</cmt>
+ <desc>11 Mbps/Ch 6/0f:06:25:05:24:3d</desc>
+ <sym>Red Square</sym>
+ </wpt>
+ <wpt lat="47.718141700" lon="-90.997521700">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>linksys/6</name>
+ <cmt>11 Mbps/Ch 6/0f:0c:41:b6:fe:62</cmt>
+ <desc>11 Mbps/Ch 6/0f:0c:41:b6:fe:62</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.718231700" lon="-90.997986700">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>linksys/7</name>
+ <cmt>54 Mbps/Ch 1/0f:0c:41:74:d0:76</cmt>
+ <desc>54 Mbps/Ch 1/0f:0c:41:74:d0:76</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.718246700" lon="-90.998141700">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>house_net</name>
+ <cmt>54 Mbps/Ch 2/0f:0f:66:0b:cf:0f</cmt>
+ <desc>54 Mbps/Ch 2/0f:0f:66:0b:cf:0f</desc>
+ <sym>Red Square</sym>
+ </wpt>
+ <wpt lat="47.718260000" lon="-90.998291700">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>NETGEAR/2</name>
+ <cmt>11 Mbps/Ch 11/0f:09:5b:6f:a7:88</cmt>
+ <desc>11 Mbps/Ch 11/0f:09:5b:6f:a7:88</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.718246700" lon="-90.998716700">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>linksys/5</name>
+ <cmt>11 Mbps/Ch 6/0f:0c:41:43:87:14</cmt>
+ <desc>11 Mbps/Ch 6/0f:0c:41:43:87:14</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.717883300" lon="-90.998921700">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>Richard</name>
+ <cmt>54 Mbps/Ch 6/4a:e2:7d:43:b0:49</cmt>
+ <desc>54 Mbps/Ch 6/4a:e2:7d:43:b0:49</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.717990000" lon="-90.998890000">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>Wireless/1</name>
+ <cmt>11 Mbps/Ch 11/0f:09:5b:39:ae:a2</cmt>
+ <desc>11 Mbps/Ch 11/0f:09:5b:39:ae:a2</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.717883300" lon="-90.998921700">
+ <time>2004-06-05T00:00:00Z</time>
+ <name>Nordge</name>
+ <cmt>54 Mbps/Ch 6/0f:0d:88:ea:b7:24</cmt>
+ <desc>54 Mbps/Ch 6/0f:0d:88:ea:b7:24</desc>
+ <sym>Red Square</sym>
+ </wpt>
+ <wpt lat="47.713376700" lon="-91.013156700">
+ <time>2004-06-06T00:00:00Z</time>
+ <name>tom</name>
+ <cmt>2 Mbps/Ch 11/0f:06:25:60:6c:b1</cmt>
+ <desc>2 Mbps/Ch 11/0f:06:25:60:6c:b1</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.713376700" lon="-91.013156700">
+ <time>2004-06-06T00:00:00Z</time>
+ <name>default/8</name>
+ <cmt>22 Mbps/Ch 6/0f:0d:88:86:cf:c9</cmt>
+ <desc>22 Mbps/Ch 6/0f:0d:88:86:cf:c9</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.713376700" lon="-91.013156700">
+ <time>2004-06-06T00:00:00Z</time>
+ <name>JJ</name>
+ <cmt>11 Mbps/Ch 1/0f:60:1d:f6:90:40</cmt>
+ <desc>11 Mbps/Ch 1/0f:60:1d:f6:90:40</desc>
+ <sym>Red Square</sym>
+ </wpt>
+ <wpt lat="47.708516700" lon="-91.013463300">
+ <time>2004-06-06T00:00:00Z</time>
+ <name>purell</name>
+ <cmt>11 Mbps/Ch 6/0f:0c:41:bc:2b:00</cmt>
+ <desc>11 Mbps/Ch 6/0f:0c:41:bc:2b:00</desc>
+ <sym>Green Square</sym>
+ </wpt>
+ <wpt lat="47.710598300" lon="-91.011196700">
+ <time>2004-06-06T00:00:00Z</time>
+ <name>Wireless</name>
+ <cmt>11 Mbps/Ch 1/0f:30:ab:16:7e:50</cmt>
+ <desc>11 Mbps/Ch 1/0f:30:ab:16:7e:50</desc>
+ <sym>Green Square</sym>
+ </wpt>
+</gpx>
--- /dev/null
+
+# Garmin Mapsource This is a binary format with some undocumented
+# fields. This test is therefore intentionally vague. We read a file,
+# convert it to GPX, then write a file as MPS, then read it back and
+# write it as GPX and compare them. Since we're writing both GPX files
+# ourselves from the same version, we're immune to changes in our own
+# GPX output.
+
+rm -fr ${TMPDIR}/ms.gpx ${TMPDIR}/ms[12].gpx
+gpsbabel -i mapsource -f ${REFERENCE}/mapsource.mps -o gpx -F ${TMPDIR}/ms1.gpx
+gpsbabel -i mapsource -f ${REFERENCE}/mapsource.mps -o mapsource -F ${TMPDIR}/ms.mps
+gpsbabel -i mapsource -f ${TMPDIR}/ms.mps -o gpx -F ${TMPDIR}/ms2.gpx
+compare ${TMPDIR}/ms1.gpx ${TMPDIR}/ms2.gpx
+
+#
+# MRCB mapsource track test
+#
+rm -f ${TMPDIR}/mps-track.mps
+gpsbabel -t -i mapsource -f ${REFERENCE}/track/mps-track.mps -o mapsource,mpsverout=3 \
+ -F ${TMPDIR}/mps-track.mps
+compare ${TMPDIR}/mps-track.mps ${REFERENCE}/track
+
+# Now do a test of reading waypoints from a track-only file - should have an empty result
+rm -f ${TMPDIR}/mps-track.mps
+gpsbabel -i mapsource -f ${REFERENCE}/track/mps-track.mps -o mapsource,mpsverout=3 \
+ -F ${TMPDIR}/mps-track.mps
+compare ${REFERENCE}/mps-empty.mps ${TMPDIR}/mps-track.mps
+
+#
+# MRCB mapsource route test
+#
+rm -f ${TMPDIR}/mps-route.mps
+gpsbabel -r -i mapsource -f ${REFERENCE}/route/route.mps -o mapsource,mpsverout=4 \
+ -F ${TMPDIR}/mps-route.mps
+compare ${REFERENCE}/route/route.mps ${TMPDIR}/mps-route.mps
+
+# Now do a test of reading tracks from a route-only file - should have an empty result
+rm -f ${TMPDIR}/mps-route.mps
+gpsbabel -t -i mapsource -f ${REFERENCE}/route/route.mps -o mapsource,mpsverout=3 \
+ -F ${TMPDIR}/mps-route.mps
+compare ${REFERENCE}/mps-empty.mps ${TMPDIR}/mps-route.mps
+++ /dev/null
-
-# Garmin Mapsource This is a binary format with some undocumented
-# fields. This test is therefore intentionally vague. We read a file,
-# convert it to GPX, then write a file as MPS, then read it back and
-# write it as GPX and compare them. Since we're writing both GPX files
-# ourselves from the same version, we're immune to changes in our own
-# GPX output.
-
-rm -fr ${TMPDIR}/ms.gpx ${TMPDIR}/ms[12].gpx
-gpsbabel -i mapsource -f ${REFERENCE}/mapsource.mps -o gpx -F ${TMPDIR}/ms1.gpx
-gpsbabel -i mapsource -f ${REFERENCE}/mapsource.mps -o mapsource -F ${TMPDIR}/ms.mps
-gpsbabel -i mapsource -f ${TMPDIR}/ms.mps -o gpx -F ${TMPDIR}/ms2.gpx
-compare ${TMPDIR}/ms1.gpx ${TMPDIR}/ms2.gpx
-
-#
-# MRCB mapsource track test
-#
-rm -f ${TMPDIR}/mps-track.mps
-gpsbabel -t -i mapsource -f ${REFERENCE}/track/mps-track.mps -o mapsource,mpsverout=3 \
- -F ${TMPDIR}/mps-track.mps
-compare ${TMPDIR}/mps-track.mps ${REFERENCE}/track
-
-# Now do a test of reading waypoints from a track-only file - should have an empty result
-rm -f ${TMPDIR}/mps-track.mps
-gpsbabel -i mapsource -f ${REFERENCE}/track/mps-track.mps -o mapsource,mpsverout=3 \
- -F ${TMPDIR}/mps-track.mps
-compare ${REFERENCE}/mps-empty.mps ${TMPDIR}/mps-track.mps
-
-#
-# MRCB mapsource route test
-#
-rm -f ${TMPDIR}/mps-route.mps
-gpsbabel -r -i mapsource -f ${REFERENCE}/route/route.mps -o mapsource,mpsverout=4 \
- -F ${TMPDIR}/mps-route.mps
-compare ${REFERENCE}/route/route.mps ${TMPDIR}/mps-route.mps
-
-# Now do a test of reading tracks from a route-only file - should have an empty result
-rm -f ${TMPDIR}/mps-route.mps
-gpsbabel -t -i mapsource -f ${REFERENCE}/route/route.mps -o mapsource,mpsverout=3 \
- -F ${TMPDIR}/mps-route.mps
-compare ${REFERENCE}/mps-empty.mps ${TMPDIR}/mps-route.mps
#
# NetStumbler Summary File (read-only)
#
-rm -f ${TMPDIR}/netstumbler.mps
-gpsbabel -i netstumbler -f ${REFERENCE}/netstumbler.txt -o mapsource -F ${TMPDIR}/netstumbler.mps
-bincompare ${TMPDIR}/netstumbler.mps ${REFERENCE}/netstumbler.mps
+rm -f ${TMPDIR}/netstumbler.gpx
+gpsbabel -i netstumbler -f ${REFERENCE}/netstumbler.txt -o gpx -F ${TMPDIR}/netstumbler.gpx
+compare ${TMPDIR}/netstumbler.gpx ${REFERENCE}/netstumbler.gpx
extern ff_vecs_t garmin_vecs;
extern ff_vecs_t gdb_vecs;
extern ff_vecs_t mapsend_vecs;
-extern ff_vecs_t mps_vecs;
extern ff_vecs_t ozi_vecs;
extern ff_vecs_t pcx_vecs;
#if MAXIMAL_ENABLED
LegacyFormat garmin_fmt {garmin_vecs};
LegacyFormat gdb_fmt {gdb_vecs};
LegacyFormat mapsend_fmt {mapsend_vecs};
- LegacyFormat mps_fmt {mps_vecs};
NmeaFormat nmea_fmt;
LegacyFormat ozi_fmt {ozi_vecs};
LegacyFormat pcx_fmt {pcx_vecs};
nullptr,
nullptr,
},
- {
- &mps_fmt,
- "mapsource",
- "Garmin MapSource - mps",
- "mps",
- nullptr,
- },
{
&nmea_fmt,
"nmea",
,
<link linkend="fmt_bcr">BCR</link>
- ,
-
- <link linkend="fmt_mapsource">Mapsource</link>
, and
<link linkend="fmt_pcx">PCX</link>
<title>Converting a pile of waypoints to a GPX route</title>
<para>
Say you you have a data file that came from CSV file that you want to convert
-to a GPX route that can be loaded into Mapsource. Use the following command:
+to a GPX route that can be loaded into Basecamp. Use the following command:
</para>
<para><userinput>gpsbabel -i csv -f blah.txt -x transform,rte=wpt -o gdb -F blah.gdb</userinput></para>
</example>
<title>Converting a pile of waypoints to a GPX track</title>
<para>
Say you you have a data file that came from CSV file that you want to convert
-to a GPX track that can be loaded into Mapsource. Use the following command:
+to a GPX track that can be loaded into Basecamp. Use the following command:
</para>
<para><userinput>gpsbabel -i csv -f blah.txt -x transform,trk=wpt -o gdb -F blah.gdb</userinput></para>
</example>
+++ /dev/null
-<para>
- This format supports the Garmin <productname>Mapsource</productname> product family.
-</para>
-<para>
- This format is based on significant reverse-engineering and guesswork.
- GPSBabel's output appears to be compatible with the various versions of
- MapSource. Icon mapping is attempted between different MapSource versions.
- Altitude is supported, but proximity and depth are not.
-</para>
-<para>
- Naming files *.mps will allow file->open in Mapsource to find the files
- more easily.
-</para>
-<para>
- Versions 3, 4, and 5 of the Mapsource data format are handled automatically
- on input. By default the output is version 5. (Until 3/2004, it was
- version 3, but since Mapsource updates are free, the convenience of
- having modern icon sets outweighs the backward compatibility concern.
- Users of other versions can either upgrade or specify the switches to
- get output in a compatible format.) Waypoints, routes, and tracklogs are
- all handled, but map sets are ignored.
-</para>
-<para>
- Information on the Garmin Mapsource format was provided by Ian Cowley and
- Mark Bradley. The code was implemented by Robert Lipe and Mark Bradley.
-</para>
-
+++ /dev/null
-<para>
-This option causes the output to be merged with a pre-existing output file.
-This allows MapSource sections that aren't handled by GPSBabel (e.g. map sets)
-to be preserved.
-</para>
+++ /dev/null
-<para>
-This option causes GPSBabel to write depth values for waypoints. Most
-input formats do not support depth values, so the default is to not write
-them.
-</para>
+++ /dev/null
-<para>
-This option causes GPSBabel to write proximity values for waypoints. Most
-input formats do not support proximity values, so the default is to not write
-them.
-</para>
+++ /dev/null
-<para>
-This option specifies the format version for the output file. The default
-is version 5, as noted above. Supported versions are 3, 4, and 5.
-</para>
-
+++ /dev/null
-<para>
-This option specifies the length of generated short names on output. The
-default is 10 characters.
-</para>
+++ /dev/null
-<para>
-This option specifies whether to allow whitespace (space, tab, etc.) in
-generated short names on output. The default is to not allow whitespace.
-</para>